OLD | NEW |
1 # Copyright (C) 2013 Google Inc. All rights reserved. | 1 # Copyright (C) 2013 Google Inc. All rights reserved. |
2 # | 2 # |
3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
5 # met: | 5 # met: |
6 # | 6 # |
7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 module_path, os.pardir, 'templates')) | 63 module_path, os.pardir, 'templates')) |
64 # Make sure extension is .py, not .pyc or .pyo, so doesn't depend on caching | 64 # Make sure extension is .py, not .pyc or .pyo, so doesn't depend on caching |
65 module_pyname = os.path.splitext(module_filename)[0] + '.py' | 65 module_pyname = os.path.splitext(module_filename)[0] + '.py' |
66 | 66 |
67 # jinja2 is in chromium's third_party directory. | 67 # jinja2 is in chromium's third_party directory. |
68 # Insert at 1 so at front to override system libraries, and | 68 # Insert at 1 so at front to override system libraries, and |
69 # after path[0] == invoking script dir | 69 # after path[0] == invoking script dir |
70 sys.path.insert(1, third_party_dir) | 70 sys.path.insert(1, third_party_dir) |
71 import jinja2 | 71 import jinja2 |
72 | 72 |
| 73 from idl_definitions import Visitor |
73 import idl_types | 74 import idl_types |
74 from idl_types import IdlType | 75 from idl_types import IdlType |
75 import v8_callback_interface | 76 import v8_callback_interface |
76 import v8_dictionary | 77 import v8_dictionary |
77 from v8_globals import includes, interfaces | 78 from v8_globals import includes, interfaces |
78 import v8_interface | 79 import v8_interface |
79 import v8_types | 80 import v8_types |
| 81 import v8_union |
80 from v8_utilities import capitalize, cpp_name, conditional_string, v8_class_name | 82 from v8_utilities import capitalize, cpp_name, conditional_string, v8_class_name |
81 from utilities import KNOWN_COMPONENTS | 83 from utilities import KNOWN_COMPONENTS, idl_filename_to_component, is_valid_comp
onent_dependency, is_testing_target |
82 | 84 |
83 | 85 |
84 def render_template(interface_info, header_template, cpp_template, | 86 def render_template(include_paths, header_template, cpp_template, |
85 template_context): | 87 template_context, component=None): |
86 template_context['code_generator'] = module_pyname | 88 template_context['code_generator'] = module_pyname |
87 | 89 |
88 # Add includes for any dependencies | 90 # Add includes for any dependencies |
89 template_context['header_includes'] = sorted( | 91 template_context['header_includes'] = sorted( |
90 template_context['header_includes']) | 92 template_context['header_includes']) |
91 includes.update(interface_info.get('dependencies_include_paths', [])) | 93 |
| 94 for include_path in include_paths: |
| 95 if component: |
| 96 dependency = idl_filename_to_component(include_path) |
| 97 assert is_valid_component_dependency(component, dependency) |
| 98 includes.add(include_path) |
| 99 |
92 template_context['cpp_includes'] = sorted(includes) | 100 template_context['cpp_includes'] = sorted(includes) |
93 | 101 |
94 header_text = header_template.render(template_context) | 102 header_text = header_template.render(template_context) |
95 cpp_text = cpp_template.render(template_context) | 103 cpp_text = cpp_template.render(template_context) |
96 return header_text, cpp_text | 104 return header_text, cpp_text |
97 | 105 |
98 | 106 |
| 107 def set_global_type_info(info_provider): |
| 108 interfaces_info = info_provider.interfaces_info |
| 109 idl_types.set_ancestors(interfaces_info['ancestors']) |
| 110 IdlType.set_callback_interfaces(interfaces_info['callback_interfaces']) |
| 111 IdlType.set_dictionaries(interfaces_info['dictionaries']) |
| 112 IdlType.set_enums(info_provider.enumerations) |
| 113 IdlType.set_implemented_as_interfaces(interfaces_info['implemented_as_interf
aces']) |
| 114 IdlType.set_garbage_collected_types(interfaces_info['garbage_collected_inter
faces']) |
| 115 IdlType.set_will_be_garbage_collected_types(interfaces_info['will_be_garbage
_collected_interfaces']) |
| 116 v8_types.set_component_dirs(interfaces_info['component_dirs']) |
| 117 |
| 118 |
| 119 def should_generate_code(definitions): |
| 120 return definitions.interfaces or definitions.dictionaries |
| 121 |
| 122 |
| 123 def depends_on_union_types(idl_type): |
| 124 """Returns true when a given idl_type depends on union containers |
| 125 directly. |
| 126 """ |
| 127 if idl_type.is_union_type: |
| 128 return True |
| 129 if idl_type.is_array_or_sequence_type: |
| 130 return idl_type.element_type.is_union_type |
| 131 return False |
| 132 |
| 133 |
| 134 class TypedefResolver(Visitor): |
| 135 def __init__(self, info_provider): |
| 136 self.info_provider = info_provider |
| 137 |
| 138 def resolve(self, definitions, definition_name): |
| 139 """Traverse definitions and resolves typedefs with the actual types.""" |
| 140 self.typedefs = {} |
| 141 for name, typedef in self.info_provider.typedefs.iteritems(): |
| 142 self.typedefs[name] = typedef.idl_type |
| 143 self.additional_includes = set() |
| 144 definitions.accept(self) |
| 145 self._update_dependencies_include_paths(definition_name) |
| 146 |
| 147 def _update_dependencies_include_paths(self, definition_name): |
| 148 interface_info = self.info_provider.interfaces_info[definition_name] |
| 149 dependencies_include_paths = interface_info['dependencies_include_paths'
] |
| 150 for include_path in self.additional_includes: |
| 151 if include_path not in dependencies_include_paths: |
| 152 dependencies_include_paths.append(include_path) |
| 153 |
| 154 def _resolve_typedefs(self, typed_object): |
| 155 """Resolve typedefs to actual types in the object.""" |
| 156 for attribute_name in typed_object.idl_type_attributes: |
| 157 try: |
| 158 idl_type = getattr(typed_object, attribute_name) |
| 159 except AttributeError: |
| 160 continue |
| 161 if not idl_type: |
| 162 continue |
| 163 resolved_idl_type = idl_type.resolve_typedefs(self.typedefs) |
| 164 if depends_on_union_types(resolved_idl_type): |
| 165 self.additional_includes.add( |
| 166 self.info_provider.include_path_for_union_types) |
| 167 # Need to re-assign the attribute, not just mutate idl_type, since |
| 168 # type(idl_type) may change. |
| 169 setattr(typed_object, attribute_name, resolved_idl_type) |
| 170 |
| 171 def visit_typed_object(self, typed_object): |
| 172 self._resolve_typedefs(typed_object) |
| 173 |
| 174 |
99 class CodeGeneratorBase(object): | 175 class CodeGeneratorBase(object): |
100 """Base class for v8 bindings generator and IDL dictionary impl generator""" | 176 """Base class for v8 bindings generator and IDL dictionary impl generator""" |
101 | 177 |
102 def __init__(self, interfaces_info, cache_dir, output_dir): | 178 def __init__(self, info_provider, cache_dir, output_dir): |
103 interfaces_info = interfaces_info or {} | 179 self.info_provider = info_provider |
104 self.interfaces_info = interfaces_info | |
105 self.jinja_env = initialize_jinja_env(cache_dir) | 180 self.jinja_env = initialize_jinja_env(cache_dir) |
106 self.output_dir = output_dir | 181 self.output_dir = output_dir |
107 | 182 self.typedef_resolver = TypedefResolver(info_provider) |
108 # Set global type info | 183 set_global_type_info(info_provider) |
109 idl_types.set_ancestors(interfaces_info['ancestors']) | |
110 IdlType.set_callback_interfaces(interfaces_info['callback_interfaces']) | |
111 IdlType.set_dictionaries(interfaces_info['dictionaries']) | |
112 IdlType.set_implemented_as_interfaces(interfaces_info['implemented_as_in
terfaces']) | |
113 IdlType.set_garbage_collected_types(interfaces_info['garbage_collected_i
nterfaces']) | |
114 IdlType.set_will_be_garbage_collected_types(interfaces_info['will_be_gar
bage_collected_interfaces']) | |
115 v8_types.set_component_dirs(interfaces_info['component_dirs']) | |
116 | 184 |
117 def generate_code(self, definitions, definition_name): | 185 def generate_code(self, definitions, definition_name): |
118 """Returns .h/.cpp code as ((path, content)...).""" | 186 """Returns .h/.cpp code as ((path, content)...).""" |
119 # Set local type info | 187 # Set local type info |
| 188 if not should_generate_code(definitions): |
| 189 return set() |
| 190 |
120 IdlType.set_callback_functions(definitions.callback_functions.keys()) | 191 IdlType.set_callback_functions(definitions.callback_functions.keys()) |
121 IdlType.set_enums((enum.name, enum.values) | 192 # Resolve typedefs |
122 for enum in definitions.enumerations.values()) | 193 self.typedef_resolver.resolve(definitions, definition_name) |
123 return self.generate_code_internal(definitions, definition_name) | 194 return self.generate_code_internal(definitions, definition_name) |
124 | 195 |
125 def generate_code_internal(self, definitions, definition_name): | 196 def generate_code_internal(self, definitions, definition_name): |
126 # This should be implemented in subclasses. | 197 # This should be implemented in subclasses. |
127 raise NotImplementedError() | 198 raise NotImplementedError() |
128 | 199 |
129 | 200 |
130 class CodeGeneratorV8(CodeGeneratorBase): | 201 class CodeGeneratorV8(CodeGeneratorBase): |
131 def __init__(self, interfaces_info, cache_dir, output_dir): | 202 def __init__(self, info_provider, cache_dir, output_dir): |
132 CodeGeneratorBase.__init__(self, interfaces_info, cache_dir, output_dir) | 203 CodeGeneratorBase.__init__(self, info_provider, cache_dir, output_dir) |
133 | 204 |
134 def output_paths(self, definition_name): | 205 def output_paths(self, definition_name): |
135 header_path = posixpath.join(self.output_dir, | 206 header_path = posixpath.join(self.output_dir, |
136 'V8%s.h' % definition_name) | 207 'V8%s.h' % definition_name) |
137 cpp_path = posixpath.join(self.output_dir, 'V8%s.cpp' % definition_name) | 208 cpp_path = posixpath.join(self.output_dir, 'V8%s.cpp' % definition_name) |
138 return header_path, cpp_path | 209 return header_path, cpp_path |
139 | 210 |
140 def generate_code_internal(self, definitions, definition_name): | 211 def generate_code_internal(self, definitions, definition_name): |
141 if definition_name in definitions.interfaces: | 212 if definition_name in definitions.interfaces: |
142 return self.generate_interface_code( | 213 return self.generate_interface_code( |
143 definitions, definition_name, | 214 definitions, definition_name, |
144 definitions.interfaces[definition_name]) | 215 definitions.interfaces[definition_name]) |
145 if definition_name in definitions.dictionaries: | 216 if definition_name in definitions.dictionaries: |
146 return self.generate_dictionary_code( | 217 return self.generate_dictionary_code( |
147 definitions, definition_name, | 218 definitions, definition_name, |
148 definitions.dictionaries[definition_name]) | 219 definitions.dictionaries[definition_name]) |
149 raise ValueError('%s is not in IDL definitions' % definition_name) | 220 raise ValueError('%s is not in IDL definitions' % definition_name) |
150 | 221 |
151 def generate_interface_code(self, definitions, interface_name, interface): | 222 def generate_interface_code(self, definitions, interface_name, interface): |
152 # Store other interfaces for introspection | 223 # Store other interfaces for introspection |
153 interfaces.update(definitions.interfaces) | 224 interfaces.update(definitions.interfaces) |
154 | 225 |
| 226 interface_info = self.info_provider.interfaces_info[interface_name] |
| 227 full_path = interface_info.get('full_path') |
| 228 component = idl_filename_to_component(full_path) |
| 229 include_paths = interface_info.get('dependencies_include_paths') |
| 230 |
155 # Select appropriate Jinja template and contents function | 231 # Select appropriate Jinja template and contents function |
156 if interface.is_callback: | 232 if interface.is_callback: |
157 header_template_filename = 'callback_interface.h' | 233 header_template_filename = 'callback_interface.h' |
158 cpp_template_filename = 'callback_interface.cpp' | 234 cpp_template_filename = 'callback_interface.cpp' |
159 interface_context = v8_callback_interface.callback_interface_context | 235 interface_context = v8_callback_interface.callback_interface_context |
| 236 elif interface.is_partial: |
| 237 interface_context = v8_interface.interface_context |
| 238 header_template_filename = 'partial_interface.h' |
| 239 cpp_template_filename = 'partial_interface.cpp' |
| 240 interface_name += 'Partial' |
| 241 assert component == 'core' |
| 242 component = 'modules' |
| 243 include_paths = interface_info.get('dependencies_other_component_inc
lude_paths') |
160 else: | 244 else: |
161 header_template_filename = 'interface.h' | 245 header_template_filename = 'interface.h' |
162 cpp_template_filename = 'interface.cpp' | 246 cpp_template_filename = 'interface.cpp' |
163 interface_context = v8_interface.interface_context | 247 interface_context = v8_interface.interface_context |
164 header_template = self.jinja_env.get_template(header_template_filename) | 248 header_template = self.jinja_env.get_template(header_template_filename) |
165 cpp_template = self.jinja_env.get_template(cpp_template_filename) | 249 cpp_template = self.jinja_env.get_template(cpp_template_filename) |
166 | 250 |
167 interface_info = self.interfaces_info[interface_name] | |
168 | |
169 template_context = interface_context(interface) | 251 template_context = interface_context(interface) |
| 252 if not interface.is_partial and not is_testing_target(full_path): |
| 253 template_context['header_includes'].add(self.info_provider.include_p
ath_for_export) |
| 254 template_context['exported'] = self.info_provider.specifier_for_expo
rt |
170 # Add the include for interface itself | 255 # Add the include for interface itself |
171 template_context['header_includes'].add(interface_info['include_path']) | 256 if IdlType(interface_name).is_typed_array: |
| 257 template_context['header_includes'].add('core/dom/DOMTypedArray.h') |
| 258 elif interface_info['include_path']: |
| 259 template_context['header_includes'].add(interface_info['include_path
']) |
172 header_text, cpp_text = render_template( | 260 header_text, cpp_text = render_template( |
173 interface_info, header_template, cpp_template, template_context) | 261 include_paths, header_template, cpp_template, template_context, |
| 262 component) |
174 header_path, cpp_path = self.output_paths(interface_name) | 263 header_path, cpp_path = self.output_paths(interface_name) |
175 return ( | 264 return ( |
176 (header_path, header_text), | 265 (header_path, header_text), |
177 (cpp_path, cpp_text), | 266 (cpp_path, cpp_text), |
178 ) | 267 ) |
179 | 268 |
180 def generate_dictionary_code(self, definitions, dictionary_name, | 269 def generate_dictionary_code(self, definitions, dictionary_name, |
181 dictionary): | 270 dictionary): |
| 271 interfaces_info = self.info_provider.interfaces_info |
182 header_template = self.jinja_env.get_template('dictionary_v8.h') | 272 header_template = self.jinja_env.get_template('dictionary_v8.h') |
183 cpp_template = self.jinja_env.get_template('dictionary_v8.cpp') | 273 cpp_template = self.jinja_env.get_template('dictionary_v8.cpp') |
184 template_context = v8_dictionary.dictionary_context(dictionary) | 274 interface_info = interfaces_info[dictionary_name] |
185 interface_info = self.interfaces_info[dictionary_name] | 275 template_context = v8_dictionary.dictionary_context( |
| 276 dictionary, interfaces_info) |
| 277 include_paths = interface_info.get('dependencies_include_paths') |
186 # Add the include for interface itself | 278 # Add the include for interface itself |
187 template_context['header_includes'].add(interface_info['include_path']) | 279 if interface_info['include_path']: |
| 280 template_context['header_includes'].add(interface_info['include_path
']) |
| 281 if not is_testing_target(interface_info.get('full_path')): |
| 282 template_context['header_includes'].add(self.info_provider.include_p
ath_for_export) |
| 283 template_context['exported'] = self.info_provider.specifier_for_expo
rt |
188 header_text, cpp_text = render_template( | 284 header_text, cpp_text = render_template( |
189 interface_info, header_template, cpp_template, template_context) | 285 include_paths, header_template, cpp_template, template_context) |
190 header_path, cpp_path = self.output_paths(dictionary_name) | 286 header_path, cpp_path = self.output_paths(dictionary_name) |
191 return ( | 287 return ( |
192 (header_path, header_text), | 288 (header_path, header_text), |
193 (cpp_path, cpp_text), | 289 (cpp_path, cpp_text), |
194 ) | 290 ) |
195 | 291 |
196 | 292 |
197 class CodeGeneratorDictionaryImpl(CodeGeneratorBase): | 293 class CodeGeneratorDictionaryImpl(CodeGeneratorBase): |
198 def __init__(self, interfaces_info, cache_dir, output_dir): | 294 def __init__(self, info_provider, cache_dir, output_dir): |
199 CodeGeneratorBase.__init__(self, interfaces_info, cache_dir, output_dir) | 295 CodeGeneratorBase.__init__(self, info_provider, cache_dir, output_dir) |
200 | 296 |
201 def output_paths(self, definition_name, interface_info): | 297 def output_paths(self, definition_name, interface_info): |
202 output_dir = posixpath.join(self.output_dir, | 298 output_dir = posixpath.join(self.output_dir, |
203 interface_info['relative_dir']) | 299 interface_info['relative_dir']) |
204 header_path = posixpath.join(output_dir, '%s.h' % definition_name) | 300 header_path = posixpath.join(output_dir, '%s.h' % definition_name) |
205 cpp_path = posixpath.join(output_dir, '%s.cpp' % definition_name) | 301 cpp_path = posixpath.join(output_dir, '%s.cpp' % definition_name) |
206 return header_path, cpp_path | 302 return header_path, cpp_path |
207 | 303 |
208 def generate_code_internal(self, definitions, definition_name): | 304 def generate_code_internal(self, definitions, definition_name): |
209 if not definition_name in definitions.dictionaries: | 305 if not definition_name in definitions.dictionaries: |
210 raise ValueError('%s is not an IDL dictionary') | 306 raise ValueError('%s is not an IDL dictionary') |
| 307 interfaces_info = self.info_provider.interfaces_info |
211 dictionary = definitions.dictionaries[definition_name] | 308 dictionary = definitions.dictionaries[definition_name] |
212 interface_info = self.interfaces_info[definition_name] | 309 interface_info = interfaces_info[definition_name] |
213 header_template = self.jinja_env.get_template('dictionary_impl.h') | 310 header_template = self.jinja_env.get_template('dictionary_impl.h') |
214 cpp_template = self.jinja_env.get_template('dictionary_impl.cpp') | 311 cpp_template = self.jinja_env.get_template('dictionary_impl.cpp') |
215 template_context = v8_dictionary.dictionary_impl_context( | 312 template_context = v8_dictionary.dictionary_impl_context( |
216 dictionary, self.interfaces_info) | 313 dictionary, interfaces_info) |
| 314 include_paths = interface_info.get('dependencies_include_paths') |
| 315 # Add union containers header file to header_includes rather than |
| 316 # cpp file so that union containers can be used in dictionary headers. |
| 317 union_container_headers = [header for header in include_paths |
| 318 if header.find('UnionTypes') > 0] |
| 319 include_paths = [header for header in include_paths |
| 320 if header not in union_container_headers] |
| 321 template_context['header_includes'].update(union_container_headers) |
| 322 if not is_testing_target(interface_info.get('full_path')): |
| 323 template_context['exported'] = self.info_provider.specifier_for_expo
rt |
| 324 template_context['header_includes'].add(self.info_provider.include_p
ath_for_export) |
217 header_text, cpp_text = render_template( | 325 header_text, cpp_text = render_template( |
218 interface_info, header_template, cpp_template, template_context) | 326 include_paths, header_template, cpp_template, template_context) |
219 header_path, cpp_path = self.output_paths( | 327 header_path, cpp_path = self.output_paths( |
220 definition_name, interface_info) | 328 cpp_name(dictionary), interface_info) |
221 return ( | 329 return ( |
222 (header_path, header_text), | 330 (header_path, header_text), |
223 (cpp_path, cpp_text), | 331 (cpp_path, cpp_text), |
| 332 ) |
| 333 |
| 334 |
| 335 class CodeGeneratorUnionType(object): |
| 336 """Generates union type container classes. |
| 337 This generator is different from CodeGeneratorV8 and |
| 338 CodeGeneratorDictionaryImpl. It assumes that all union types are already |
| 339 collected. It doesn't process idl files directly. |
| 340 """ |
| 341 def __init__(self, info_provider, cache_dir, output_dir, target_component): |
| 342 self.info_provider = info_provider |
| 343 self.jinja_env = initialize_jinja_env(cache_dir) |
| 344 self.output_dir = output_dir |
| 345 self.target_component = target_component |
| 346 set_global_type_info(info_provider) |
| 347 |
| 348 def generate_code(self): |
| 349 union_types = self.info_provider.union_types |
| 350 if not union_types: |
| 351 return () |
| 352 header_template = self.jinja_env.get_template('union.h') |
| 353 cpp_template = self.jinja_env.get_template('union.cpp') |
| 354 template_context = v8_union.union_context( |
| 355 union_types, self.info_provider.interfaces_info) |
| 356 template_context['code_generator'] = module_pyname |
| 357 capitalized_component = self.target_component.capitalize() |
| 358 template_context['exported'] = self.info_provider.specifier_for_export |
| 359 template_context['header_filename'] = 'bindings/%s/v8/UnionTypes%s.h' %
( |
| 360 self.target_component, capitalized_component) |
| 361 template_context['macro_guard'] = 'UnionType%s_h' % capitalized_componen
t |
| 362 additional_header_includes = [self.info_provider.include_path_for_export
] |
| 363 |
| 364 # Add UnionTypesCore.h as a dependency when we generate modules union ty
pes |
| 365 # because we only generate union type containers which are used by both |
| 366 # core and modules in UnionTypesCore.h. |
| 367 # FIXME: This is an ad hoc workaround and we need a general way to |
| 368 # handle core <-> modules dependency. |
| 369 if self.target_component == 'modules': |
| 370 additional_header_includes.append( |
| 371 'bindings/core/v8/UnionTypesCore.h') |
| 372 |
| 373 template_context['header_includes'] = sorted( |
| 374 template_context['header_includes'] + additional_header_includes) |
| 375 |
| 376 header_text = header_template.render(template_context) |
| 377 cpp_text = cpp_template.render(template_context) |
| 378 header_path = posixpath.join(self.output_dir, |
| 379 'UnionTypes%s.h' % capitalized_component) |
| 380 cpp_path = posixpath.join(self.output_dir, |
| 381 'UnionTypes%s.cpp' % capitalized_component) |
| 382 return ( |
| 383 (header_path, header_text), |
| 384 (cpp_path, cpp_text), |
224 ) | 385 ) |
225 | 386 |
226 | 387 |
227 def initialize_jinja_env(cache_dir): | 388 def initialize_jinja_env(cache_dir): |
228 jinja_env = jinja2.Environment( | 389 jinja_env = jinja2.Environment( |
229 loader=jinja2.FileSystemLoader(templates_dir), | 390 loader=jinja2.FileSystemLoader(templates_dir), |
230 # Bytecode cache is not concurrency-safe unless pre-cached: | 391 # Bytecode cache is not concurrency-safe unless pre-cached: |
231 # if pre-cached this is read-only, but writing creates a race condition. | 392 # if pre-cached this is read-only, but writing creates a race condition. |
232 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir), | 393 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir), |
233 keep_trailing_newline=True, # newline-terminate generated files | 394 keep_trailing_newline=True, # newline-terminate generated files |
234 lstrip_blocks=True, # so can indent control flow tags | 395 lstrip_blocks=True, # so can indent control flow tags |
235 trim_blocks=True) | 396 trim_blocks=True) |
236 jinja_env.filters.update({ | 397 jinja_env.filters.update({ |
237 'blink_capitalize': capitalize, | 398 'blink_capitalize': capitalize, |
238 'conditional': conditional_if_endif, | 399 'conditional': conditional_if_endif, |
239 'exposed': exposed_if, | 400 'exposed': exposed_if, |
240 'per_context_enabled': per_context_enabled_if, | |
241 'runtime_enabled': runtime_enabled_if, | 401 'runtime_enabled': runtime_enabled_if, |
242 }) | 402 }) |
243 return jinja_env | 403 return jinja_env |
244 | 404 |
245 | 405 |
246 def generate_indented_conditional(code, conditional): | 406 def generate_indented_conditional(code, conditional): |
247 # Indent if statement to level of original code | 407 # Indent if statement to level of original code |
248 indent = re.match(' *', code).group(0) | 408 indent = re.match(' *', code).group(0) |
249 return ('%sif (%s) {\n' % (indent, conditional) + | 409 return ('%sif (%s) {\n' % (indent, conditional) + |
250 ' %s\n' % '\n '.join(code.splitlines()) + | 410 ' %s\n' % '\n '.join(code.splitlines()) + |
(...skipping 10 matching lines...) Expand all Loading... |
261 '#endif // %s\n' % conditional_string) | 421 '#endif // %s\n' % conditional_string) |
262 | 422 |
263 | 423 |
264 # [Exposed] | 424 # [Exposed] |
265 def exposed_if(code, exposed_test): | 425 def exposed_if(code, exposed_test): |
266 if not exposed_test: | 426 if not exposed_test: |
267 return code | 427 return code |
268 return generate_indented_conditional(code, 'context && (%s)' % exposed_test) | 428 return generate_indented_conditional(code, 'context && (%s)' % exposed_test) |
269 | 429 |
270 | 430 |
271 # [PerContextEnabled] | |
272 def per_context_enabled_if(code, per_context_enabled_function): | |
273 if not per_context_enabled_function: | |
274 return code | |
275 return generate_indented_conditional(code, 'context && context->isDocument()
&& %s(toDocument(context))' % per_context_enabled_function) | |
276 | |
277 | |
278 # [RuntimeEnabled] | 431 # [RuntimeEnabled] |
279 def runtime_enabled_if(code, runtime_enabled_function_name): | 432 def runtime_enabled_if(code, runtime_enabled_function_name): |
280 if not runtime_enabled_function_name: | 433 if not runtime_enabled_function_name: |
281 return code | 434 return code |
282 return generate_indented_conditional(code, '%s()' % runtime_enabled_function
_name) | 435 return generate_indented_conditional(code, '%s()' % runtime_enabled_function
_name) |
283 | 436 |
284 | 437 |
285 ################################################################################ | 438 ################################################################################ |
286 | 439 |
287 def main(argv): | 440 def main(argv): |
(...skipping 15 matching lines...) Expand all Loading... |
303 | 456 |
304 # Create a dummy file as output for the build system, | 457 # Create a dummy file as output for the build system, |
305 # since filenames of individual cache files are unpredictable and opaque | 458 # since filenames of individual cache files are unpredictable and opaque |
306 # (they are hashes of the template path, which varies based on environment) | 459 # (they are hashes of the template path, which varies based on environment) |
307 with open(dummy_filename, 'w') as dummy_file: | 460 with open(dummy_filename, 'w') as dummy_file: |
308 pass # |open| creates or touches the file | 461 pass # |open| creates or touches the file |
309 | 462 |
310 | 463 |
311 if __name__ == '__main__': | 464 if __name__ == '__main__': |
312 sys.exit(main(sys.argv)) | 465 sys.exit(main(sys.argv)) |
OLD | NEW |