1# Copyright 2019 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4""" 5This module provides C++ language specific implementations of 6code_node.CodeNode. 7""" 8 9from .code_node import CodeNode 10from .code_node import CompositeNode 11from .code_node import Likeliness 12from .code_node import ListNode 13from .code_node import SymbolScopeNode 14from .code_node import TextNode 15from .codegen_expr import CodeGenExpr 16from .codegen_format import format_template 17 18 19class CxxBlockNode(CompositeNode): 20 def __init__(self, body): 21 template_format = ( 22 "{{\n" # 23 " {body}\n" 24 "}}") 25 26 CompositeNode.__init__( 27 self, 28 template_format, 29 body=_to_symbol_scope_node(body, Likeliness.ALWAYS)) 30 31 32class CxxIfNode(CompositeNode): 33 def __init__(self, cond, body, likeliness): 34 template_format = ( 35 "if ({cond}) {{\n" # 36 " {body}\n" 37 "}}") 38 39 CompositeNode.__init__( 40 self, 41 template_format, 42 cond=_to_conditional_node(cond), 43 body=_to_symbol_scope_node(body, likeliness)) 44 45 46class CxxIfElseNode(CompositeNode): 47 def __init__(self, cond, then, then_likeliness, else_, else_likeliness): 48 template_format = ( 49 "if ({cond}) {{\n" # 50 " {then}\n" 51 "}} else {{\n" 52 " {else_}\n" 53 "}}") 54 55 CompositeNode.__init__( 56 self, 57 template_format, 58 cond=_to_conditional_node(cond), 59 then=_to_symbol_scope_node(then, then_likeliness), 60 else_=_to_symbol_scope_node(else_, else_likeliness)) 61 62 63class CxxLikelyIfNode(CxxIfNode): 64 def __init__(self, cond, body): 65 CxxIfNode.__init__(self, cond, body, Likeliness.LIKELY) 66 67 68class CxxUnlikelyIfNode(CxxIfNode): 69 def __init__(self, cond, body): 70 CxxIfNode.__init__(self, cond, body, Likeliness.UNLIKELY) 71 72 73class CxxMultiBranchesNode(CodeNode): 74 class _Clause(object): 75 def __init__(self, cond, body): 76 assert isinstance(cond, (CodeNode, bool)) 77 assert isinstance(body, SymbolScopeNode) 78 self.cond = cond 79 self.body = body 80 81 def __init__(self): 82 clauses_gensym = CodeNode.gensym() 83 clauses = [] 84 template_text = format_template( 85 """\ 86% for {clause} in {clauses}: 87% if not loop.first: 88 else \\ 89% endif 90% if {clause}.cond is not False: 91% if {clause}.cond is not True: 92if (${{{clause}.cond}}) \\ 93% endif 94{{ 95 ${{{clause}.body}} 96}}\\ 97% if {clause}.cond is True: 98 <% break %> 99% endif 100% endif 101% endfor\ 102""", 103 clause=CodeNode.gensym(), 104 clauses=clauses_gensym) 105 template_vars = {clauses_gensym: clauses} 106 107 CodeNode.__init__( 108 self, template_text=template_text, template_vars=template_vars) 109 110 self._clauses = clauses 111 112 def append(self, cond, body, likeliness=Likeliness.LIKELY): 113 if cond is None: 114 cond = False 115 elif isinstance(cond, CodeGenExpr): 116 if cond.is_always_true: 117 cond = True 118 elif cond.is_always_false: 119 cond = False 120 121 if not isinstance(cond, bool): 122 cond = _to_conditional_node(cond) 123 body = _to_symbol_scope_node(body, likeliness) 124 125 if isinstance(cond, CodeNode): 126 cond.set_outer(self) 127 body.set_outer(self) 128 129 self._clauses.append(self._Clause(cond, body)) 130 131 132class CxxBreakableBlockNode(CompositeNode): 133 def __init__(self, body, likeliness=Likeliness.LIKELY): 134 template_format = ("do {{ // Dummy loop for use of 'break'.\n" 135 " {body}\n" 136 "}} while (false);") 137 138 CompositeNode.__init__( 139 self, 140 template_format, 141 body=_to_symbol_scope_node(body, likeliness)) 142 143 144class CxxFuncDeclNode(CompositeNode): 145 def __init__(self, 146 name, 147 arg_decls, 148 return_type, 149 template_params=None, 150 static=False, 151 explicit=False, 152 constexpr=False, 153 const=False, 154 override=False, 155 default=False, 156 delete=False): 157 """ 158 Args: 159 name: Function name. 160 arg_decls: List of argument declarations. 161 return_type: Return type. 162 template_params: List of template parameters or None. 163 static: True makes this a static function. 164 explicit: True makes this an explicit constructor. 165 constexpr: True makes this a constexpr function. 166 const: True makes this a const function. 167 override: True makes this an overriding function. 168 default: True makes this have the default implementation. 169 delete: True makes this function be deleted. 170 """ 171 assert isinstance(static, bool) 172 assert isinstance(explicit, bool) 173 assert isinstance(constexpr, bool) 174 assert isinstance(const, bool) 175 assert isinstance(override, bool) 176 assert isinstance(default, bool) 177 assert isinstance(delete, bool) 178 assert not (default and delete) 179 180 template_format = ("{template}" 181 "{static}{explicit}{constexpr}" 182 "{return_type} " 183 "{name}({arg_decls})" 184 "{const}" 185 "{override}" 186 "{default_or_delete}" 187 ";") 188 189 if template_params is None: 190 template = "" 191 else: 192 template = "template <{}>\n".format(", ".join(template_params)) 193 194 static = "static " if static else "" 195 explicit = "explicit " if explicit else "" 196 constexpr = "constexpr " if constexpr else "" 197 const = " const" if const else "" 198 override = " override" if override else "" 199 200 if default: 201 default_or_delete = " = default" 202 elif delete: 203 default_or_delete = " = delete" 204 else: 205 default_or_delete = "" 206 207 CompositeNode.__init__( 208 self, 209 template_format, 210 name=_to_maybe_text_node(name), 211 arg_decls=ListNode( 212 map(_to_maybe_text_node, arg_decls), separator=", "), 213 return_type=_to_maybe_text_node(return_type), 214 template=template, 215 static=static, 216 explicit=explicit, 217 constexpr=constexpr, 218 const=const, 219 override=override, 220 default_or_delete=default_or_delete) 221 222 223class CxxFuncDefNode(CompositeNode): 224 def __init__(self, 225 name, 226 arg_decls, 227 return_type, 228 class_name=None, 229 template_params=None, 230 static=False, 231 inline=False, 232 explicit=False, 233 constexpr=False, 234 const=False, 235 override=False, 236 member_initializer_list=None): 237 """ 238 Args: 239 name: Function name. 240 arg_decls: List of argument declarations. 241 return_type: Return type. 242 class_name: Class name to be used as nested-name-specifier. 243 template_params: List of template parameters or None. 244 static: True makes this a static function. 245 inline: True makes this an inline function. 246 explicit: True makes this an explicit constructor. 247 constexpr: True makes this a constexpr function. 248 const: True makes this a const function. 249 override: True makes this an overriding function. 250 member_initializer_list: List of member initializers. 251 """ 252 assert isinstance(static, bool) 253 assert isinstance(inline, bool) 254 assert isinstance(explicit, bool) 255 assert isinstance(constexpr, bool) 256 assert isinstance(const, bool) 257 assert isinstance(override, bool) 258 259 template_format = ("{template}" 260 "{static}{inline}{explicit}{constexpr}" 261 "{return_type} " 262 "{class_name}{name}({arg_decls})" 263 "{const}" 264 "{override}" 265 "{member_initializer_list} {{\n" 266 " {body}\n" 267 "}}") 268 269 if class_name is None: 270 class_name = "" 271 else: 272 class_name = ListNode([_to_maybe_text_node(class_name)], tail="::") 273 274 if template_params is None: 275 template = "" 276 else: 277 template = "template <{}>\n".format(", ".join(template_params)) 278 279 static = "static " if static else "" 280 inline = "inline " if inline else "" 281 explicit = "explicit " if explicit else "" 282 constexpr = "constexpr " if constexpr else "" 283 const = " const" if const else "" 284 override = " override" if override else "" 285 286 if member_initializer_list is None: 287 member_initializer_list = "" 288 else: 289 member_initializer_list = ListNode( 290 map(_to_maybe_text_node, member_initializer_list), 291 separator=", ", 292 head=" : ") 293 294 self._body_node = SymbolScopeNode() 295 296 CompositeNode.__init__( 297 self, 298 template_format, 299 name=_to_maybe_text_node(name), 300 arg_decls=ListNode( 301 map(_to_maybe_text_node, arg_decls), separator=", "), 302 return_type=_to_maybe_text_node(return_type), 303 class_name=class_name, 304 template=template, 305 static=static, 306 inline=inline, 307 explicit=explicit, 308 constexpr=constexpr, 309 const=const, 310 override=override, 311 member_initializer_list=member_initializer_list, 312 body=self._body_node) 313 314 @property 315 def body(self): 316 return self._body_node 317 318 319class CxxClassDefNode(CompositeNode): 320 def __init__(self, name, base_class_names=None, final=False, export=None): 321 """ 322 Args: 323 name: The class name to be defined. 324 base_class_names: The list of base class names. 325 final: True makes this a final class. 326 export: Class export annotation. 327 """ 328 assert isinstance(final, bool) 329 330 template_format = ("class{export} {name}{final}{base_clause} {{\n" 331 " {top_section}\n" 332 " {public_section}\n" 333 " {protected_section}\n" 334 " {private_section}\n" 335 " {bottom_section}\n" 336 "}};") 337 338 if export is None: 339 export = "" 340 else: 341 export = ListNode([_to_maybe_text_node(export)], head=" ") 342 343 final = " final" if final else "" 344 345 if base_class_names is None: 346 base_clause = "" 347 else: 348 base_specifier_list = [ 349 CompositeNode( 350 "public {base_class_name}", 351 base_class_name=_to_maybe_text_node(base_class_name)) 352 for base_class_name in base_class_names 353 ] 354 base_clause = ListNode( 355 base_specifier_list, separator=", ", head=" : ") 356 357 self._top_section = ListNode(tail="\n") 358 self._public_section = ListNode(head="public:\n", tail="\n") 359 self._protected_section = ListNode(head="protected:\n", tail="\n") 360 self._private_section = ListNode(head="private:\n", tail="\n") 361 self._bottom_section = ListNode() 362 363 CompositeNode.__init__( 364 self, 365 template_format, 366 name=_to_maybe_text_node(name), 367 base_clause=base_clause, 368 final=final, 369 export=export, 370 top_section=self._top_section, 371 public_section=self._public_section, 372 protected_section=self._protected_section, 373 private_section=self._private_section, 374 bottom_section=self._bottom_section) 375 376 @property 377 def top_section(self): 378 return self._top_section 379 380 @property 381 def public_section(self): 382 return self._public_section 383 384 @property 385 def protected_section(self): 386 return self._protected_section 387 388 @property 389 def private_section(self): 390 return self._private_section 391 392 @property 393 def bottom_section(self): 394 return self._bottom_section 395 396 397class CxxNamespaceNode(CompositeNode): 398 def __init__(self, name="", body=None): 399 template_format = ("namespace {name} {{\n" 400 "\n" 401 "{body}\n" 402 "\n" 403 "}} // namespace {name}") 404 405 if body is None: 406 self._body = ListNode() 407 else: 408 self._body = _to_list_node(body) 409 410 CompositeNode.__init__( 411 self, template_format, name=name, body=self._body) 412 413 @property 414 def body(self): 415 return self._body 416 417 418def _to_conditional_node(cond): 419 if isinstance(cond, CodeNode): 420 return cond 421 if isinstance(cond, CodeGenExpr): 422 return TextNode(cond.to_text()) 423 if isinstance(cond, str): 424 return TextNode(cond) 425 assert False 426 427 428def _to_list_node(node): 429 if isinstance(node, ListNode): 430 return node 431 if isinstance(node, CodeNode): 432 return ListNode([node]) 433 if isinstance(node, (list, tuple)): 434 return ListNode(node) 435 assert False 436 437 438def _to_maybe_text_node(node): 439 if isinstance(node, CodeNode): 440 return node 441 if isinstance(node, str): 442 return TextNode(node) 443 assert False 444 445 446def _to_symbol_scope_node(node, likeliness): 447 if isinstance(node, SymbolScopeNode): 448 pass 449 elif isinstance(node, CodeNode): 450 node = SymbolScopeNode([node]) 451 elif isinstance(node, (list, tuple)): 452 node = SymbolScopeNode(node) 453 else: 454 assert False 455 node.set_likeliness(likeliness) 456 return node 457