1# -*- python -*- 2# Package : omniidl 3# defs.py Created on: 1999/11/2 4# Author : David Scott (djs) 5# 6# Copyright (C) 2003-2011 Apasphere Ltd 7# Copyright (C) 1999 AT&T Laboratories Cambridge 8# 9# This file is part of omniidl. 10# 11# omniidl is free software; you can redistribute it and/or modify it 12# under the terms of the GNU General Public License as published by 13# the Free Software Foundation; either version 2 of the License, or 14# (at your option) any later version. 15# 16# This program is distributed in the hope that it will be useful, 17# but WITHOUT ANY WARRANTY; without even the implied warranty of 18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19# General Public License for more details. 20# 21# You should have received a copy of the GNU General Public License 22# along with this program. If not, see http://www.gnu.org/licenses/ 23# 24# Description: 25# 26# Produce the main header definitions for the C++ backend 27 28"""Produce the main header definitions""" 29 30from omniidl import idlast, idltype 31from omniidl_be.cxx import id, output, config, types, iface, cxx, ast, util 32from omniidl_be.cxx import value 33from omniidl_be.cxx.header import template 34 35# We behave as if the global code here is really inside a class 36import sys 37self = sys.modules[__name__] 38 39stream = None 40 41_insideClass = 0 42_insideModule = 0 43_insideInterface = 0 44_interfaces = {} 45_completedModules = {} 46 47def pushInsideClass(): 48 global _insideClass 49 _insideClass = _insideClass + 1 50 51def popInsideClass(): 52 global _insideClass 53 _insideClass = _insideClass - 1 54 55def pushInsideModule(): 56 global _insideModule 57 _insideModule = _insideModule + 1 58 59def popInsideModule(): 60 global _insideModule 61 _insideModule = _insideModule - 1 62 63def pushInsideInterface(): 64 global _insideInterface 65 _insideInterface = _insideInterface + 1 66 67def popInsideInterface(): 68 global _insideInterface 69 _insideInterface = _insideInterface - 1 70 71 72def init(_stream): 73 global stream, _insideClass, _insideModule, _insideInterface 74 global _interfaces, _completedModules 75 76 stream = _stream 77 78 # Need to keep track of how deep within the AST we are. 79 # In a recursive procedure these would be extra arguments, 80 # but the visitor pattern necessitates them being global. 81 _insideInterface = 0 82 _insideModule = 0 83 _insideClass = 0 84 85 # A repository id entry in this hash indicates that an interface 86 # has been declared- therefore any more AST forward nodes for this 87 # interface are ignored. 88 _interfaces = {} 89 90 # When we first encounter a module, we sometimes deal with all the 91 # continuations straight away. Therefore when we reencounter a 92 # continuation later, we don't duplicate the definitions. 93 _completedModules = {} 94 95 return self 96 97 98# Returns the prefix required inside a const declaration (it depends on 99# exactly what the declaration is nested inside) 100def const_qualifier(insideModule=None, insideClass=None): 101 if insideModule is None: 102 insideModule = _insideModule 103 insideClass = _insideClass 104 105 if not insideModule and not insideClass: 106 return "_CORBA_GLOBAL_VAR" 107 elif insideClass: 108 return "static" 109 else: 110 return "_CORBA_MODULE_VAR" 111 112# Same logic for function qualifiers 113def func_qualifier(): 114 return const_qualifier(_insideModule, _insideClass) 115 116# Inline functions are subtly different 117def inline_qualifier(): 118 if not _insideModule and not _insideClass: 119 return "inline" 120 elif _insideClass: 121 return "static inline" 122 else: 123 return "_CORBA_MODULE_INLINE" 124 125 126# 127# Control arrives here 128# 129def visitAST(node): 130 global stream, _insideClass, _insideModule, _insideInterface 131 global _interfaces, _completedModules 132 133 _insideInterface = 0 134 _insideModule = 0 135 _insideClass = 0 136 _interfaces = {} 137 _completedModules = {} 138 139 for n in node.declarations(): 140 if ast.shouldGenerateCodeForDecl(n): 141 n.accept(self) 142 143def visitModule(node): 144 # Ensure we only output the definitions once. 145 # In particular, when the splice-modules flag is set and this is 146 # a reopened module, the node will be marked as completed already. 147 if node in _completedModules: 148 return 149 _completedModules[node] = 1 150 151 ident = node.identifier() 152 cxx_id = id.mapID(ident) 153 154 if not config.state['Fragment']: 155 stream.out(template.module_begin, name = cxx_id) 156 stream.inc_indent() 157 158 # push self.__insideModule, true 159 pushInsideModule() 160 161 for n in node.definitions(): 162 n.accept(self) 163 164 # deal with continuations (only if the splice-modules flag is set) 165 if config.state['Splice Modules']: 166 for c in node.continuations(): 167 for n in c.definitions(): 168 n.accept(self) 169 _completedModules[c] = 1 170 171 popInsideModule() 172 173 if not config.state['Fragment']: 174 stream.dec_indent() 175 stream.out(template.module_end, name = cxx_id) 176 177 178 179def visitInterface(node): 180 # It's legal to have a forward interface declaration after 181 # the actual interface definition. Make sure we ignore these. 182 _interfaces[node.repoId()] = 1 183 184 name = node.identifier() 185 cxx_name = id.mapID(name) 186 187 outer_environment = id.lookup(node) 188 outer_environment.enter(name) 189 190 pushInsideInterface() 191 pushInsideClass() 192 193 # make the necessary forward references, typedefs and define 194 # the _Helper class 195 I = iface.Interface(node) 196 197 I_Helper = iface.I_Helper(I) 198 I_Helper.hh(stream) 199 200 # recursively take care of other IDL declared within this 201 # scope (evaluate function later- lazy eval though 'thunking') 202 def Other_IDL(node = node): 203 for n in node.declarations(): 204 n.accept(self) 205 206 # Output this interface's corresponding class 207 Ibase = iface.I(I,Other_IDL) 208 Ibase.hh(stream) 209 210 if not node.local(): 211 _objref_I = iface._objref_I(I) 212 _objref_I.hh(stream) 213 214 _pof_I = iface._pof_I(I) 215 _pof_I.hh(stream) 216 217 # Skeleton class 218 _impl_I = iface._impl_I(I) 219 _impl_I.hh(stream) 220 221 # Generate BOA compatible skeletons? 222 if config.state['BOA Skeletons']: 223 _sk_I = iface._sk_I(I) 224 _sk_I.hh(stream) 225 226 popInsideClass() 227 popInsideInterface() 228 229 # Typecode and Any 230 if config.state['Typecode']: 231 qualifier = const_qualifier(_insideModule, _insideClass) 232 stream.out(template.typecode, 233 qualifier = qualifier, 234 name = cxx_name) 235 236 return 237 238 239def visitForward(node): 240 # Note it's legal to have multiple forward declarations 241 # of the same name. So ignore the duplicates. 242 if node.repoId() in _interfaces: 243 return 244 _interfaces[node.repoId()] = 1 245 246 environment = id.lookup(node) 247 name = id.Name(node.scopedName()) 248 guard = name.guard() 249 250 # Potentially forward declare BOA skeleton class 251 class_sk = "" 252 if config.state['BOA Skeletons']: 253 class_sk = "class _sk_" + name.simple() + ";" 254 255 # output the definition 256 if node.abstract(): 257 stream.out(template.abstract_interface_Helper, 258 guard = guard, 259 class_sk_name = class_sk, 260 name = name.simple()) 261 elif node.local(): 262 stream.out(template.local_interface_Helper, 263 guard = guard, 264 class_sk_name = class_sk, 265 name = name.simple()) 266 else: 267 stream.out(template.interface_Helper, 268 guard = guard, 269 class_sk_name = class_sk, 270 name = name.simple()) 271 272 273def visitConst(node): 274 environment = id.lookup(node) 275 276 constType = types.Type(node.constType()) 277 d_constType = constType.deref() 278 if d_constType.string(): 279 type_string = "char *" 280 elif d_constType.wstring(): 281 type_string = "::CORBA::WChar *" 282 elif d_constType.fixed(): 283 type_string = constType.member() 284 else: 285 type_string = d_constType.member() 286 # should this be .base? 287 288 cxx_name = id.mapID(node.identifier()) 289 290 value = d_constType.literal(node.value(), environment) 291 292 representedByInteger = d_constType.representable_by_int() 293 294 # depends on whether we are inside a class / in global scope 295 # etc 296 # should be rationalised with tyutil.const_qualifier 297 if _insideClass: 298 if representedByInteger: 299 stream.out(template.const_inclass_isinteger, 300 type = type_string, name = cxx_name, val = value) 301 else: 302 stream.out(template.const_inclass_notinteger, 303 type = type_string, name = cxx_name) 304 else: 305 where = "GLOBAL" 306 if _insideModule: 307 where = "MODULE" 308 if representedByInteger: 309 stream.out(template.const_outsideclass_isinteger, 310 where = where, 311 type = type_string, 312 name = cxx_name, 313 val = value) 314 else: 315 stream.out(template.const_outsideclass_notinteger, 316 where = where, 317 type = type_string, 318 name = cxx_name) 319 320 321def visitTypedef(node): 322 environment = id.lookup(node) 323 324 is_global_scope = not (_insideModule or _insideInterface) 325 326 aliasType = types.Type(node.aliasType()) 327 328 # is _this_ type a constructed type? 329 if node.constrType(): 330 node.aliasType().decl().accept(self) 331 332 d_type = aliasType.deref() 333 derefTypeID = d_type.base(environment) 334 335 basicReferencedTypeID = aliasType.member(environment) 336 337 # each one is handled independently 338 for d in node.declarators(): 339 340 # derivedName is the new typedef'd name 341 # alias_dims is a list of dimensions of the type being aliased 342 343 derivedName = id.mapID(d.identifier()) 344 345 alias_dims = aliasType.dims() 346 347 # array_declarator indicates whether this is a simple (non-array) 348 # declarator or not 349 array_declarator = d.sizes() != [] 350 351 # Typecode and Any 352 if config.state['Typecode']: 353 qualifier = const_qualifier(_insideModule,_insideClass) 354 stream.out(template.typecode, 355 qualifier = qualifier, 356 name = derivedName) 357 358 # is it a simple alias (ie not an array at this level)? 359 if not array_declarator: 360 # not an array declarator but a simple declarator to an array 361 if aliasType.array(): 362 # simple alias to an array should alias all the 363 # array handling functions, but we don't need to duplicate 364 # array looping code since we can just call the functions 365 # for the base type 366 stream.out(template.typedef_simple_to_array, 367 base = basicReferencedTypeID, 368 derived = derivedName, 369 qualifier = func_qualifier(), 370 inline_qualifier = inline_qualifier()) 371 372 # Non-array of string 373 elif d_type.string(): 374 stream.out(template.typedef_simple_string, 375 name = derivedName) 376 elif d_type.wstring(): 377 stream.out(template.typedef_simple_wstring, 378 name = derivedName) 379 elif d_type.typecode(): 380 stream.out(template.typedef_simple_typecode, 381 name = derivedName) 382 elif d_type.any(): 383 stream.out(template.typedef_simple_any, 384 name = derivedName) 385 386 elif d_type.fixed(): 387 stream.out(template.typedef_simple_fixed, 388 name = derivedName, 389 digits = d_type.type().digits(), 390 scale = d_type.type().scale()) 391 392 # Non-array of basic type 393 elif isinstance(d_type.type(), idltype.Base): 394 stream.out(template.typedef_simple_basic, 395 base = basicReferencedTypeID, 396 derived = derivedName) 397 398 # a typedef to a struct or union, or a typedef to a 399 # typedef to a sequence 400 elif d_type.struct() or d_type.structforward() or \ 401 d_type.union() or d_type.unionforward() or \ 402 (d_type.sequence() and aliasType.typedef()): 403 404 stream.out(template.typedef_simple_constructed, 405 base = basicReferencedTypeID, 406 name = derivedName) 407 408 # Non-array of object reference 409 elif d_type.interface(): 410 derefTypeID = derefTypeID.replace("_ptr","") 411 # Note that the base name is fully flattened 412 is_CORBA_Object = d_type.type().scopedName() ==\ 413 ["CORBA", "Object"] 414 impl_base = "" 415 objref_base = "" 416 sk_base = "" 417 if not is_CORBA_Object: 418 scopedName = d_type.type().decl().scopedName() 419 name = id.Name(scopedName) 420 impl_scopedName = name.prefix("_impl_") 421 objref_scopedName = name.prefix("_objref_") 422 sk_scopedName = name.prefix("_sk_") 423 impl_name = impl_scopedName.unambiguous(environment) 424 objref_name = objref_scopedName.unambiguous(environment) 425 sk_name = sk_scopedName.unambiguous(environment) 426 427 impl_base = "typedef " + impl_name + " _impl_" +\ 428 derivedName + ";" 429 objref_base = "typedef " + objref_name + " _objref_" +\ 430 derivedName + ";" 431 sk_base = "typedef " + sk_name + " _sk_" +\ 432 derivedName + ";" 433 434 stream.out(template.typedef_simple_objref, 435 base = derefTypeID, 436 name = derivedName, 437 impl_base = impl_base, 438 objref_base = objref_base) 439 if config.state['BOA Skeletons']: 440 stream.out(sk_base) 441 442 # Non-array of valuetype 443 elif d_type.value() or d_type.valuebox(): 444 basicReferencedTypeID = basicReferencedTypeID.replace("_member", 445 "") 446 stream.out(template.typedef_simple_constructed, 447 base = basicReferencedTypeID, 448 name = derivedName) 449 450 # Non-array of enum 451 elif d_type.enum(): 452 stream.out(template.typedef_simple_basic, 453 base = basicReferencedTypeID, 454 derived = derivedName) 455 456 # Non-array of sequence 457 elif d_type.sequence(): 458 seqType = types.Type(d_type.type().seqType()) 459 d_seqType = seqType.deref() 460 bounded = d_type.type().bound() 461 462 templateName = d_type.sequenceTemplate(environment) 463 464 if d_seqType.structforward() or d_seqType.unionforward(): 465 # Sequence of forward-declared struct or union. 466 # We cannot use the normal sequence templates 467 # since they have inline methods that require the 468 # full definition of the member type. We use 469 # templates with abstract virtual functions 470 # instead. 471 472 element = element_ptr = seqType.base(environment) 473 474 def bounds(bounded = bounded, 475 derivedName = derivedName, 476 derived = templateName, 477 element = element): 478 if bounded: 479 ct = template.sequence_bounded_ctors 480 else: 481 ct = template.sequence_unbounded_ctors 482 stream.out(ct, name = derivedName, element=element, 483 bound=bounded, derived=derived) 484 485 stream.out(template.sequence_forward_type, 486 name = derivedName, 487 derived = templateName, 488 element = element, 489 bounds = bounds) 490 491 else: 492 # Normal case using a template class. 493 494 if seqType.array(): 495 element = "*** INVALID" 496 element_ptr = seqType.base(environment) 497 else: 498 if d_seqType.string(): 499 element = "_CORBA_String_element" 500 element_ptr = "char*" 501 elif d_seqType.wstring(): 502 element = "_CORBA_WString_element" 503 element_ptr = "::CORBA::WChar*" 504 elif d_seqType.interface(): 505 element = seqType.base(environment) 506 element_ptr = element 507 elif d_seqType.value() or d_seqType.valuebox(): 508 element = seqType.base(environment) 509 element_ptr = element + "*" 510 # only if an anonymous sequence 511 elif seqType.sequence(): 512 element = d_seqType.sequenceTemplate(environment) 513 element_ptr = element 514 elif d_seqType.typecode(): 515 element = "::CORBA::TypeCode_member" 516 element_ptr = element 517 else: 518 element = seqType.base(environment) 519 element_ptr = element 520 521 # enums are a special case 522 # ---- 523 # gcc requires that the marshalling operators for the 524 # element be declared before the sequence template is 525 # typedef'd. This is a problem for enums, as the 526 # marshalling operators are not yet defined (and are 527 # not part of the type itself). 528 # ---- 529 # Note that the fully dereferenced name is used 530 friend = "friend" 531 if is_global_scope: 532 friend = "" 533 534 if d_seqType.enum() and not seqType.array(): 535 stream.out(template.typedef_enum_oper_friend, 536 element = d_seqType.base(environment), 537 friend = friend) 538 539 # derivedName is the new type identifier 540 # element is the name of the basic element type 541 # templateName contains the template instantiation 542 543 def bounds(bounded = bounded, derivedName = derivedName, 544 element_ptr = element_ptr, 545 templateName = templateName): 546 if bounded: 547 ctor_template = template.sequence_bounded_ctors 548 else: 549 ctor_template = template.sequence_unbounded_ctors 550 stream.out(ctor_template, 551 name = derivedName, 552 element = element_ptr, 553 derived = templateName) 554 555 # output the main sequence definition 556 stream.out(template.sequence_type, 557 name = derivedName, 558 derived = templateName, 559 bounds = bounds) 560 561 562 # start building the _var and _out types 563 element_reference = "*** INVALID" 564 if not aliasType.array(): 565 if d_seqType.string(): 566 # special case alert 567 element_reference = element 568 elif d_seqType.wstring(): 569 # special case alert 570 element_reference = element 571 elif d_seqType.interface(): 572 element_reference = d_seqType.objRefTemplate("Element", 573 environment) 574 elif d_seqType.value() or d_seqType.valuebox(): 575 element_reference = d_seqType.valueTemplate("Element", 576 environment) 577 # only if an anonymous sequence 578 elif seqType.sequence(): 579 element_reference = d_seqType.sequenceTemplate(environment) + "&" 580 else: 581 element_reference = element + "&" 582 583 def subscript_operator_var(stream = stream, 584 is_array = seqType.array(), 585 element_ptr = element_ptr, 586 element_ref = element_reference): 587 588 if is_array: 589 stream.out(template.sequence_var_array_subscript, 590 element = element_ptr) 591 else: 592 stream.out(template.sequence_var_subscript, 593 element = element_ref) 594 595 def subscript_operator_out(stream = stream, 596 is_array = seqType.array(), 597 element_ptr = element_ptr, 598 element_ref = element_reference): 599 if is_array: 600 stream.out(template.sequence_out_array_subscript, 601 element = element_ptr) 602 else: 603 stream.out(template.sequence_out_subscript, 604 element = element_ref) 605 606 # write the _var class definition 607 stream.out(template.sequence_var, 608 name = derivedName, 609 subscript_operator = subscript_operator_var) 610 611 # write the _out class definition 612 stream.out(template.sequence_out, 613 name = derivedName, 614 subscript_operator = subscript_operator_out) 615 616 else: 617 util.fatalError("Inexhaustive Case Match") 618 619 620 # ---------------------------------------------------------------- 621 # declarator is an array typedef declarator 622 elif array_declarator: 623 624 all_dims = d.sizes() + alias_dims 625 dimsString = cxx.dimsToString(d.sizes()) 626 taildims = cxx.dimsToString(d.sizes()[1:]) 627 628 typestring = aliasType.member(environment) 629 630 # build the _dup loop 631 def dup_loop(stream = stream, all_dims = all_dims): 632 loop = cxx.For(stream, all_dims) 633 stream.out("\n_data@index@ = _s@index@;\n", 634 index = loop.index()) 635 loop.end() 636 637 # build the _copy loop 638 def copy_loop(stream = stream, all_dims = all_dims): 639 loop = cxx.For(stream, all_dims) 640 stream.out("\n_to@index@ = _from@index@;\n", 641 index = loop.index()) 642 loop.end() 643 644 stream.out(template.typedef_array, 645 name = derivedName, 646 type = typestring, 647 dims = dimsString, 648 taildims = taildims, 649 firstdim = repr(all_dims[0]), 650 dup_loop = dup_loop, 651 copy_loop = copy_loop, 652 qualifier = func_qualifier(), 653 inline_qualifier = inline_qualifier()) 654 655 # output the _copyHelper class 656 fqname = id.Name(d.scopedName()).fullyQualify() 657 658 if types.variableDecl(node): 659 stream.out(template.typedef_array_copyHelper, 660 var_or_fix = "Variable", 661 name = derivedName, 662 fqname = fqname) 663 664 stream.out(template.typedef_array_variable_out_type, 665 name = derivedName) 666 else: 667 stream.out(template.typedef_array_copyHelper, 668 var_or_fix = "Fix", 669 name = derivedName, 670 fqname = fqname) 671 672 stream.out(template.typedef_array_fix_out_type, 673 name = derivedName) 674 675 676 677def visitMember(node): 678 memberType = node.memberType() 679 if node.constrType(): 680 # if the type was declared here, it must be an instance 681 # of idltype.Declared! 682 assert isinstance(memberType, idltype.Declared) 683 memberType.decl().accept(self) 684 685 686def visitStruct(node): 687 name = node.identifier() 688 cxx_name = id.mapID(name) 689 690 outer_environment = id.lookup(node) 691 environment = outer_environment.enter(name) 692 693 pushInsideClass() 694 695 # Deal with types constructed here 696 def Other_IDL(stream = stream, node = node, environment = environment): 697 for m in node.members(): 698 if m.constrType(): 699 m.memberType().decl().accept(self) 700 701 # Deal with the actual struct members 702 def members(stream = stream, node = node, environment = environment): 703 for m in node.members(): 704 memberType = types.Type(m.memberType()) 705 706 memtype = memberType.member(environment) 707 708 for d in m.declarators(): 709 ident = d.identifier() 710 711 cxx_id = id.mapID(ident) 712 713 decl_dims = d.sizes() 714 is_array_declarator = decl_dims != [] 715 716 # non-arrays of direct sequences are done via a typedef 717 if not is_array_declarator and memberType.sequence(): 718 stream.out(template.struct_nonarray_sequence, 719 memtype = memtype, 720 cxx_id = cxx_id) 721 else: 722 dims_string = cxx.dimsToString(decl_dims) 723 if is_array_declarator: 724 stream.out(template.struct_array_declarator, 725 memtype = memtype, 726 cxx_id = cxx_id, 727 dims = dims_string, 728 tail_dims = cxx.dimsToString(d.sizes()[1:]), 729 prefix = config.state['Private Prefix']) 730 731 stream.out(template.struct_normal_member, 732 memtype = memtype, 733 cxx_id = cxx_id, 734 dims = dims_string) 735 736 # Output the structure itself 737 if types.variableDecl(node): 738 stream.out(template.struct, 739 name = cxx_name, 740 fix_or_var = "Variable", 741 Other_IDL = Other_IDL, 742 members = members) 743 stream.out(template.struct_variable_out_type, 744 name = cxx_name) 745 else: 746 stream.out(template.struct, 747 name = cxx_name, 748 fix_or_var = "Fix", 749 Other_IDL = Other_IDL, 750 members = members) 751 stream.out(template.struct_fix_out_type, 752 name = cxx_name) 753 754 755 popInsideClass() 756 757 # TypeCode and Any 758 if config.state['Typecode']: 759 # structs in C++ are classes with different default privacy policies 760 qualifier = const_qualifier(_insideModule, _insideClass) 761 stream.out(template.typecode, 762 qualifier = qualifier, 763 name = cxx_name) 764 765 766def visitStructForward(node): 767 cxx_name = id.mapID(node.identifier()) 768 stream.out(template.struct_forward, name = cxx_name) 769 770 771def visitException(node): 772 exname = node.identifier() 773 774 cxx_exname = id.mapID(exname) 775 776 outer_environment = id.lookup(node) 777 environment = outer_environment.enter(exname) 778 779 pushInsideClass() 780 781 # if the exception has no members, inline some no-ops 782 no_members = (node.members() == []) 783 784 # other types constructed within this one 785 def Other_IDL(stream = stream, node = node): 786 for m in node.members(): 787 if m.constrType(): 788 m.memberType().decl().accept(self) 789 790 # deal with the exceptions members 791 def members(stream = stream, node = node, environment = environment): 792 for m in node.members(): 793 memberType = types.Type(m.memberType()) 794 795 for d in m.declarators(): 796 decl_dims = d.sizes() 797 is_array_declarator = decl_dims != [] 798 799 memtype = memberType.member(environment) 800 ident = d.identifier() 801 802 cxx_id = id.mapID(ident) 803 804 dims_string = cxx.dimsToString(decl_dims) 805 806 if is_array_declarator: 807 stream.out(template.exception_array_declarator, 808 memtype = memtype, 809 cxx_id = cxx_id, 810 dims = dims_string, 811 tail_dims = cxx.dimsToString(d.sizes()[1:]), 812 private_prefix = config.state['Private Prefix']) 813 814 stream.out(template.exception_member, 815 memtype = memtype, 816 cxx_id = cxx_id, 817 dims = dims_string) 818 819 # deal with ctor args 820 ctor_args = [] 821 for m in node.members(): 822 memberType = types.Type(m.memberType()) 823 d_memberType = memberType.deref() 824 for d in m.declarators(): 825 decl_dims = d.sizes() 826 is_array_declarator = decl_dims != [] 827 ctor_arg_type = memberType.op(types.IN, environment) 828 # sequences are not passed by reference here 829 if d_memberType.sequence(): 830 if memberType.typedef(): 831 ctor_arg_type = "const " + id.Name(memberType.type().decl().scopedName()).unambiguous(environment) 832 else: 833 ctor_arg_type = "const " + memberType.sequenceTemplate(environment) 834 elif d_memberType.typecode(): 835 ctor_arg_type = "::CORBA::TypeCode_ptr" 836 837 ident = d.identifier() 838 839 cxx_id = id.mapID(ident) 840 841 if is_array_declarator: 842 ctor_arg_type = "const " + config.state['Private Prefix'] +\ 843 "_" + cxx_id 844 ctor_args.append(ctor_arg_type + " i_" + cxx_id) 845 846 847 ctor = "" 848 if ctor_args != []: 849 ctor = cxx_exname + "(" + ", ".join(ctor_args) + ");" 850 851 if no_members: 852 inline = "inline " 853 body = "{ }" 854 alignedSize = "" 855 else: 856 inline = "" 857 body = ";" 858 alignedSize = "size_t _NP_alignedSize(size_t) const;" 859 860 # output the main exception declaration 861 stream.out(template.exception, 862 name = cxx_exname, 863 Other_IDL = Other_IDL, 864 members = members, 865 constructor = ctor, 866 alignedSize = alignedSize, 867 inline = inline, 868 body = body) 869 870 popInsideClass() 871 872 # Typecode and Any 873 if config.state['Typecode']: 874 qualifier = const_qualifier(_insideModule, _insideClass) 875 stream.out(template.typecode, 876 qualifier = qualifier, 877 name = cxx_exname) 878 879 880 881def visitUnion(node): 882 ident = node.identifier() 883 884 cxx_id = id.mapID(ident) 885 outer_environment = id.lookup(node) 886 environment = outer_environment.enter(ident) 887 888 pushInsideClass() 889 890 switchType = types.Type(node.switchType()) 891 d_switchType = switchType.deref() 892 893 #################################################################### 894 # in the case where there is no default case and an implicit default 895 # member, choose a discriminator value to set. Note that attempting 896 # to access the data is undefined 897 def chooseArbitraryDefault(switchType = switchType, 898 values = ast.allCaseLabelValues(node), 899 environment = environment): 900 901 # dereference the switch_type (ie if CASE <scoped_name>) 902 switchType = switchType.deref() 903 904 # for integer types, find the lowest unused number 905 def min_unused(start, used = values): 906 x = start 907 while x in used: 908 x = x + 1 909 return x 910 911 kind = switchType.type().kind() 912 if switchType.integer(): 913 (low, high) = ast.integer_type_ranges[kind] 914 s = switchType.literal(min_unused(low+1)) 915 return s 916 917 # for other types, first compute the set of all legal values 918 # (sets are all fairly small) 919 elif kind == idltype.tk_char: 920 all = list(map(chr, list(range(0, 255)))) 921 elif kind == idltype.tk_boolean: 922 all = [0, 1] 923 elif kind == idltype.tk_enum: 924 all = switchType.type().decl().enumerators() 925 else: 926 util.fatalError("Failed to generate a default union " 927 "discriminator value") 928 929 for item in all: 930 if item not in values: 931 return switchType.literal(item, environment) 932 933 return None 934 # 935 ############################################################### 936 937 # does the IDL union have any default case? 938 # It'll be handy to know which case is the default one later- 939 # so add a new attribute to mark it 940 ast.markDefaultCase(node) 941 hasDefault = ast.defaultCase(node) != None 942 943 # CORBA 2.3 C++ Mapping 1-34 944 # "A union has an implicit default member if it does not have 945 # a default case and not all permissible values of the union 946 # discriminant are listed" 947 exhaustive = ast.exhaustiveMatch(switchType, ast.allCaseLabelValues(node)) 948 implicitDefault = not hasDefault and not exhaustive 949 950 if types.variableDecl(node): 951 fixed = "Variable" 952 else: 953 fixed = "Fix" 954 955 def Other_IDL(stream = stream, node = node): 956 # deal with constructed switch type 957 if node.constrType(): 958 node.switchType().decl().accept(self) 959 960 # deal with children defined in this scope 961 for n in node.cases(): 962 if n.constrType(): 963 n.caseType().decl().accept(self) 964 965 966 # create the default constructor body 967 def default_constructor(stream = stream, 968 implicitDefault = implicitDefault, 969 hasDefault = hasDefault, 970 choose = chooseArbitraryDefault): 971 if implicitDefault: 972 stream.out(template.union_constructor_implicit) 973 elif hasDefault: 974 stream.out(template.union_constructor_default, 975 default = choose()) 976 return 977 978 def ctor_cases(stream = stream, node = node, switchType = switchType, 979 environment = environment, exhaustive = exhaustive): 980 981 booleanWrap = switchType.boolean() and exhaustive 982 trueName = None 983 984 for c in node.cases(): 985 for l in c.labels(): 986 if l.default(): continue 987 988 discrimvalue = switchType.literal(l.value(), environment) 989 name = id.mapID(c.declarator().identifier()) 990 991 if booleanWrap and discrimvalue == "1": 992 trueName = name 993 994 stream.out(template.union_ctor_case, 995 discrimvalue = discrimvalue, 996 name = name) 997 998 # Booleans are a special case (isn't everything?) 999 if booleanWrap: 1000 stream.out(template.union_ctor_bool_default, 1001 name = trueName) 1002 else: 1003 stream.out(template.union_ctor_default) 1004 return 1005 1006 # create the copy constructor and the assignment operator 1007 # bodies 1008 def copy_constructor(stream = stream, exhaustive = exhaustive, 1009 node = node, ctor_cases = ctor_cases): 1010 if not exhaustive: 1011 # grab the default case 1012 default = "_release_member();" 1013 for c in node.cases(): 1014 if c.isDefault: 1015 case_id = c.declarator().identifier() 1016 cxx_case_id = id.mapID(case_id) 1017 default = cxx_case_id + "(_value." + cxx_case_id + "());" 1018 1019 1020 stream.out(template.union_ctor_nonexhaustive, 1021 default = default, 1022 cases = ctor_cases) 1023 else: 1024 stream.out(template.union_ctor_exhaustive, 1025 cases = ctor_cases) 1026 return 1027 1028 # do we need an implicit _default function? 1029 def implicit_default(stream = stream, choose = chooseArbitraryDefault, 1030 implicitDefault = implicitDefault): 1031 1032 if implicitDefault: 1033 stream.out(template.union_implicit_default, 1034 arbitraryDefault = choose()) 1035 return 1036 1037 # The body of the union _d(_value) function generated here 1038 def _d_fn(stream = stream, node = node, switchType = switchType, 1039 implicitDefault = implicitDefault, 1040 environment = environment): 1041 1042 # The plan: 1043 # * Check the _pd__initialised flag is set, else throw BAD_PARAM 1044 # * Check for the simple case where _value == _pd__d and return 1045 # * Have a nested switch, the outer switch is keyed on the current 1046 # discriminator value and the inner one is the requested new value 1047 # 1048 # Possibilities: 1049 # * Could perform some code minimisation eg for the case 1050 # union foo switch(boolean){ 1051 # case TRUE: 1052 # case FALSE: 1053 # T bar; 1054 # }; 1055 # This is equivalent to a single default: case and no switch is 1056 # required. 1057 1058 # Make sure we don't output a switch with no cases (if there is a 1059 # one-to-one mapping of labels to cases) 1060 need_switch = 0 1061 1062 # Need to fill in a default case only if the union has none itself 1063 outer_has_default = 0 1064 1065 cases = output.StringStream() 1066 1067 # Produce a set of "case <foo>: goto fail;" for every label 1068 # except those in an exception list 1069 def fail_all_but(exceptions, node = node, cases = cases, 1070 switchType = switchType, environment = environment): 1071 for c in node.cases(): 1072 for l in c.labels(): 1073 if l not in exceptions: 1074 cases.out("case @label@: goto fail;", 1075 label = switchType.literal(l.value(), 1076 environment)) 1077 1078 1079 # switch (currently active case){ 1080 # 1081 outer_has_default = 0 # only mention default: once 1082 for c in node.cases(): 1083 1084 need_switch = 1 1085 1086 # If the currently active case has only one non-default label, 1087 # then the only legal action is to set it to its current value. 1088 # We've already checked for this in an if (...) statement before 1089 # here. 1090 if len(c.labels()) == 1 and not c.labels()[0].default(): 1091 cases.out("case @label@: goto fail;", 1092 label = switchType.literal(c.labels()[0].value(), 1093 environment)) 1094 continue 1095 1096 # output one C++ case label for each IDL case label 1097 # case 1: 1098 # case 2: 1099 # default: 1100 1101 this_case_is_default = 0 1102 for l in c.labels(): 1103 if l.default(): 1104 this_case_is_default = 1 1105 outer_has_default = 1 1106 cases.out("default:") 1107 continue 1108 1109 cases.out("case @label@:", 1110 label = switchType.literal(l.value(), environment)) 1111 1112 # switch (case to switch to){ 1113 # 1114 cases.inc_indent() 1115 cases.out("switch (_value){\n") 1116 cases.inc_indent() 1117 1118 # If we currently are in the default case, fail all attempts 1119 # to switch cases. 1120 if this_case_is_default: 1121 fail_all_but(c.labels()) 1122 cases.out("default: _pd__d = _value; return;") 1123 cases.dec_indent() 1124 cases.out("}\n") 1125 cases.dec_indent() 1126 continue 1127 1128 # This is not the default case, all possibilities have associated 1129 # UnionCaseLabels 1130 for l in c.labels(): 1131 cases.out("case @label@: _pd__d = @label@; return;", 1132 label = switchType.literal(l.value(), environment)) 1133 1134 1135 cases.out("default: goto fail;") 1136 cases.dec_indent() 1137 cases.out("}\n") 1138 cases.dec_indent() 1139 1140 if not outer_has_default and not implicitDefault: 1141 cases.out("default: goto fail;") 1142 1143 # handle situation where have an implicit default member 1144 # (ie no actual case, but a legal set of discriminator values) 1145 # (assumes that the current discriminator is set to one of the 1146 # defaults) 1147 if implicitDefault: 1148 need_switch = 1 1149 cases.out("default:") 1150 cases.out("switch (_value){") 1151 cases.inc_indent() 1152 # again, make sure we aren't currently in the default state 1153 # and trying to set the discriminator to a non-default state 1154 fail_all_but([]) 1155 1156 cases.out("default: _pd__d = _value; return;") 1157 1158 cases.dec_indent() 1159 cases.out("}") 1160 1161 1162 # output the code here 1163 switch = output.StringStream() 1164 if need_switch: 1165 switch.out("switch (_pd__d){\n @cases@\n};", cases = cases) 1166 stream.out(template.union_d_fn_body, switch = switch) 1167 1168 1169 # get and set functions for each case: 1170 def members(stream = stream, node = node, environment = environment, 1171 switchType = switchType): 1172 1173 for c in node.cases(): 1174 # Following the typedef chain will deliver the base type of 1175 # the alias. Whether or not it is an array is stored in an 1176 # ast.Typedef node. 1177 caseType = types.Type(c.caseType()) 1178 d_caseType = caseType.deref() 1179 1180 # the mangled name of the member 1181 decl = c.declarator() 1182 decl_dims = decl.sizes() 1183 1184 full_dims = decl_dims + caseType.dims() 1185 1186 is_array = full_dims != [] 1187 is_array_declarator = decl_dims != [] 1188 1189 member = id.mapID(decl.identifier()) 1190 1191 memtype = caseType.member(environment) 1192 1193 # Pick a discriminator value to use when selecting the 1194 # case. Pick the first non-default label if there is one. 1195 labels = c.labels() 1196 1197 label = labels[0] 1198 if label.default() and len(labels) > 1: 1199 # Pick a non-default label if there is one 1200 label = labels[1] 1201 1202 discrimvalue = switchType.literal(label.value(), environment) 1203 1204 1205 # only different when array declarator 1206 const_type_str = memtype 1207 1208 # create typedefs for anonymous arrays 1209 if is_array_declarator: 1210 prefix = config.state['Private Prefix'] 1211 stream.out(template.union_array_declarator, 1212 prefix = prefix, 1213 memtype = memtype, 1214 name = member, 1215 dims = cxx.dimsToString(decl.sizes()), 1216 tail_dims = cxx.dimsToString(decl.sizes()[1:])) 1217 const_type_str = prefix + "_" + member 1218 memtype = "_" + member 1219 1220 if is_array: 1221 # build the loop 1222 def loop(stream = stream, full_dims = full_dims, 1223 member = member): 1224 loop = cxx.For(stream, full_dims) 1225 index = loop.index() 1226 stream.out("\n_pd_" + member + index + " = _value" +\ 1227 index + ";\n") 1228 loop.end() 1229 return 1230 1231 stream.out(template.union_array, 1232 memtype = memtype, 1233 const_type = const_type_str, 1234 name = member, 1235 isDefault = str(c.isDefault), 1236 discrimvalue = discrimvalue, 1237 first_dim = repr(full_dims[0]), 1238 loop = loop) 1239 1240 elif d_caseType.any(): 1241 # note type != CORBA::Any when its an alias... 1242 stream.out(template.union_any, 1243 type = memtype, 1244 name = member, 1245 isDefault = str(c.isDefault), 1246 discrimvalue = discrimvalue) 1247 1248 elif d_caseType.typecode(): 1249 stream.out(template.union_typecode, 1250 name = member, 1251 isDefault = str(c.isDefault), 1252 discrimvalue = discrimvalue) 1253 1254 elif isinstance(d_caseType.type(), idltype.Base) or \ 1255 d_caseType.enum(): 1256 # basic type 1257 stream.out(template.union_basic, 1258 type = memtype, 1259 name = member, 1260 isDefault = str(c.isDefault), 1261 discrimvalue = discrimvalue) 1262 1263 elif d_caseType.string(): 1264 stream.out(template.union_string, 1265 type = memtype, 1266 name = member, 1267 isDefault = str(c.isDefault), 1268 discrimvalue = discrimvalue) 1269 1270 elif d_caseType.wstring(): 1271 stream.out(template.union_wstring, 1272 name = member, 1273 isDefault = str(c.isDefault), 1274 discrimvalue = discrimvalue) 1275 1276 elif d_caseType.interface(): 1277 scopedName = d_caseType.type().decl().scopedName() 1278 1279 name = id.Name(scopedName) 1280 ptr_name = name.suffix("_ptr").unambiguous(environment) 1281 var_name = name.suffix("_var").unambiguous(environment) 1282 1283 if isinstance(d_caseType.type().decl(), idlast.Forward): 1284 helper = name.suffix("_Helper").unambiguous(environment) 1285 duplicate = helper + "::duplicate" 1286 else: 1287 iclass = name.unambiguous(environment) 1288 duplicate = iclass + "::_duplicate" 1289 1290 stream.out(template.union_objref, 1291 member = member, 1292 memtype = memtype, 1293 ptr_name = ptr_name, 1294 var_name = var_name, 1295 duplicate = duplicate, 1296 isDefault = str(c.isDefault), 1297 discrimvalue = discrimvalue) 1298 1299 elif caseType.typedef() or d_caseType.struct() or \ 1300 d_caseType.union() or d_caseType.fixed(): 1301 stream.out(template.union_constructed, 1302 type = memtype, 1303 name = member, 1304 isDefault = str(c.isDefault), 1305 discrimvalue = discrimvalue) 1306 1307 elif d_caseType.sequence(): 1308 sequence_template = d_caseType.sequenceTemplate(environment) 1309 stream.out(template.union_sequence, 1310 sequence_template = sequence_template, 1311 member = member, 1312 isDefault = str(c.isDefault), 1313 discrimvalue = discrimvalue) 1314 1315 elif d_caseType.value() or d_caseType.valuebox(): 1316 scopedName = d_caseType.type().decl().scopedName() 1317 name = id.Name(scopedName) 1318 type = name.unambiguous(environment) 1319 1320 stream.out(template.union_value, 1321 member=member, 1322 type=type, 1323 isDefault = str(c.isDefault), 1324 discrimvalue = discrimvalue) 1325 1326 else: 1327 util.fatalError("Unknown union case type encountered") 1328 1329 return 1330 1331 # declare the instance of the discriminator and 1332 # the actual data members (shock, horror) 1333 union_body = output.StringStream() 1334 release_body = output.StringStream() 1335 need_release = 0 1336 explicit_default = 0 1337 1338 for c in node.cases(): 1339 1340 # find the dereferenced type of the member if it's an alias 1341 caseType = types.Type(c.caseType()) 1342 d_caseType = caseType.deref() 1343 case_kind = d_caseType.type().kind() 1344 1345 decl = c.declarator() 1346 decl_dims = decl.sizes() 1347 full_dims = caseType.dims() + decl_dims 1348 1349 is_array = full_dims != [] 1350 is_array_declarator = decl_dims != [] 1351 1352 member_name = id.mapID(c.declarator().identifier()) 1353 member_type = caseType.base(environment) 1354 1355 1356 # Work out type for the union member 1357 if is_array_declarator: 1358 # _slice typedef defined earlier 1359 member_type = "_" + member_name + "_slice*" 1360 1361 elif caseType.sequence(): 1362 # _seq typedef defined earlier 1363 member_type = "_" + member_name + "_seq*" 1364 1365 elif is_array: 1366 member_type = member_type + "_slice*" 1367 1368 elif case_kind in [ idltype.tk_any, 1369 idltype.tk_struct, 1370 idltype.tk_union, 1371 idltype.tk_sequence, 1372 idltype.tk_except, 1373 idltype.tk_fixed, 1374 idltype.tk_value, 1375 idltype.tk_value_box, 1376 ]: 1377 member_type = member_type + "*" 1378 1379 # Float types have conditional code that may or may not store 1380 # them by pointer. 1381 if not is_array and case_kind in [ idltype.tk_float, 1382 idltype.tk_double ]: 1383 union_member = template.union_member_float 1384 else: 1385 union_member = template.union_member 1386 1387 # Output union member 1388 union_body.out(union_member, 1389 type = member_type, 1390 name = member_name) 1391 1392 1393 # Code to release the member 1394 release = None 1395 helper = None 1396 1397 if is_array: 1398 release = template.union_release_array 1399 1400 elif case_kind in [ idltype.tk_any, 1401 idltype.tk_struct, 1402 idltype.tk_union, 1403 idltype.tk_sequence, 1404 idltype.tk_except, 1405 idltype.tk_fixed, 1406 ]: 1407 release = template.union_release_delete 1408 1409 elif case_kind in [ idltype.tk_objref, 1410 idltype.tk_abstract_interface, 1411 idltype.tk_local_interface, 1412 ]: 1413 1414 if isinstance(d_caseType.type().decl(), idlast.Forward): 1415 # Use the helper class to call release 1416 release = template.union_release_helper 1417 1418 scopedName = d_caseType.type().decl().scopedName() 1419 name = id.Name(scopedName) 1420 helper = name.suffix("_Helper").unambiguous(environment) 1421 else: 1422 release = template.union_release_corba_release 1423 1424 elif case_kind in [ idltype.tk_TypeCode, 1425 ]: 1426 release = template.union_release_corba_release 1427 1428 elif case_kind in [ idltype.tk_value, 1429 idltype.tk_value_box, 1430 ]: 1431 release = template.union_release_valuetype 1432 1433 elif case_kind == idltype.tk_string: 1434 release = template.union_release_string 1435 1436 elif case_kind == idltype.tk_wstring: 1437 release = template.union_release_wstring 1438 1439 if release is not None: 1440 need_release = 1 1441 release_member = output.StringStream() 1442 release_member.out(release, name=member_name, helper=helper) 1443 else: 1444 release_member = "" 1445 1446 cases = output.StringStream() 1447 for label in c.labels(): 1448 if label.default(): 1449 cases.out("default:") 1450 explicit_default = 1 1451 else: 1452 cases.out("case @label@:", 1453 label = switchType.literal(label.value(), 1454 environment)) 1455 1456 release_body.out(template.union_release_case, 1457 cases = cases, 1458 release_member = release_member) 1459 1460 if need_release: 1461 if not explicit_default: 1462 # Output an empty default case to prevent fussy compilers 1463 # complaining 1464 release_body.out(template.union_release_case, 1465 cases = "default:", 1466 release_member = "") 1467 1468 release_member = output.StringStream() 1469 release_member.out(template.union_release_member, 1470 cases = release_body) 1471 else: 1472 release_member = template.union_release_member_empty 1473 1474 # write out the union class 1475 stream.out(template.union, 1476 unionname = cxx_id, 1477 fixed = fixed, 1478 Other_IDL = Other_IDL, 1479 default_constructor = default_constructor, 1480 copy_constructor = copy_constructor, 1481 discrimtype = d_switchType.base(environment), 1482 _d_body = _d_fn, 1483 implicit_default = implicit_default, 1484 members = members, 1485 union_body = union_body, 1486 release_member = release_member) 1487 1488 if types.variableDecl(node): 1489 stream.out(template.union_variable_out_type, 1490 unionname = cxx_id) 1491 else: 1492 stream.out(template.union_fix_out_type, 1493 unionname = cxx_id) 1494 1495 popInsideClass() 1496 1497 # TypeCode and Any 1498 if config.state['Typecode']: 1499 qualifier = const_qualifier(_insideModule, _insideClass) 1500 stream.out(template.typecode, 1501 qualifier = qualifier, 1502 name = cxx_id) 1503 1504 return 1505 1506 1507def visitUnionForward(node): 1508 cxx_name = id.mapID(node.identifier()) 1509 stream.out(template.union_forward, name = cxx_name) 1510 1511 1512def visitEnum(node): 1513 name = id.mapID(node.identifier()) 1514 1515 enumerators = node.enumerators() 1516 memberlist = [id.Name(x.scopedName()).simple() for x in enumerators] 1517 stream.out(template.enum, 1518 name = name, 1519 memberlist = ", ".join(memberlist)) 1520 1521 # TypeCode and Any 1522 if config.state['Typecode']: 1523 qualifier = const_qualifier(_insideModule, _insideClass) 1524 stream.out(template.typecode, 1525 qualifier = qualifier, name = name) 1526 1527 return 1528 1529def visitValue(node): 1530 v = value.getValueType(node) 1531 v.module_decls(stream, self) 1532 1533def visitValueAbs(node): 1534 v = value.getValueType(node) 1535 v.module_decls(stream, self) 1536 1537def visitValueForward(node): 1538 v = value.getValueType(node) 1539 v.module_decls(stream, self) 1540 1541def visitValueBox(node): 1542 v = value.getValueType(node) 1543 v.module_decls(stream, self) 1544