# -*- python -*-
# Package : omniidl
# skutil.py Created on: 1999/11/15
# Author : David Scott (djs)
#
# Copyright (C) 2003-2008 Apasphere Ltd
# Copyright (C) 1999 AT&T Laboratories Cambridge
#
# This file is part of omniidl.
#
# omniidl is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
# Description:
#
# Skeleton utility functions designed for the C++ backend
# $Id: skutil.py,v 1.20.2.13 2009/05/06 16:15:52 dgrisby Exp $
# $Log: skutil.py,v $
# Revision 1.20.2.13 2009/05/06 16:15:52 dgrisby
# Update lots of copyright notices.
#
# Revision 1.20.2.12 2008/12/03 10:53:58 dgrisby
# Tweaks leading to Python 3 support; other minor clean-ups.
#
# Revision 1.20.2.11 2007/09/19 14:16:08 dgrisby
# Avoid namespace clashes if IDL defines modules named CORBA.
#
# Revision 1.20.2.10 2007/04/12 19:50:32 dgrisby
# A few cases of sizeof(bool) > 1 were not handled correctly.
#
# Revision 1.20.2.9 2006/04/28 18:40:46 dgrisby
# Merge from omni4_0_develop.
#
# Revision 1.20.2.8 2005/11/09 12:22:17 dgrisby
# Local interfaces support.
#
# Revision 1.20.2.7 2005/08/16 13:51:21 dgrisby
# Problems with valuetype / abstract interface C++ mapping.
#
# Revision 1.20.2.6 2005/01/06 23:09:50 dgrisby
# Big merge from omni4_0_develop.
#
# Revision 1.20.2.5 2004/10/13 17:58:22 dgrisby
# Abstract interfaces support; values support interfaces; value bug fixes.
#
# Revision 1.20.2.4 2004/02/16 10:10:30 dgrisby
# More valuetype, including value boxes. C++ mapping updates.
#
# Revision 1.20.2.3 2003/10/23 11:25:54 dgrisby
# More valuetype support.
#
# Revision 1.20.2.2 2003/05/20 16:53:14 dgrisby
# Valuetype marshalling support.
#
# Revision 1.20.2.1 2003/03/23 21:02:41 dgrisby
# Start of omniORB 4.1.x development branch.
#
# Revision 1.17.2.9 2001/06/19 16:41:49 sll
# Type cast now correctly distinguishes between normal and array types.
#
# Revision 1.17.2.8 2001/06/19 14:23:21 sll
# In the marshalling and unmarshalling code, only cast from a sequence T_var to
# T&. Otherwise, the generate code is wrong with gcc 3.0. Suppose T is a
# sequence of A, even though T is always a derived class of the template
# instance seq<A>, casting a T_var to a seq<A>& causes GCC 3.0 to generate
# wrong code quietly!
#
# Revision 1.17.2.7 2001/06/15 10:22:09 sll
# Work around for MSVC++ bug. Changed the casting of the array of base types
# when they are marshalled using the quick method.
#
# Revision 1.17.2.6 2001/06/08 17:12:13 dpg1
# Merge all the bug fixes from omni3_develop.
#
# Revision 1.17.2.5 2001/04/19 10:04:13 dpg1
# Bug in sort_exceptions()
#
# Revision 1.17.2.4 2000/11/07 18:28:21 sll
# Use helper marshal functions if the interface is a forward declaration.
#
# Revision 1.17.2.3 2000/11/03 19:26:01 sll
# Simplified the marshalling functions.
#
# Revision 1.17.2.2 2000/10/12 15:37:48 sll
# Updated from omni3_1_develop.
#
# Revision 1.18.2.2 2000/08/21 11:34:35 djs
# Lots of omniidl/C++ backend changes
#
# Revision 1.18.2.1 2000/08/04 17:10:26 dpg1
# Long long support
#
# Revision 1.18 2000/07/13 15:26:01 dpg1
# Merge from omni3_develop for 3.0 release.
#
# Revision 1.15.2.4 2000/05/31 18:02:16 djs
# Better output indenting (and preprocessor directives now correctly output at
# the beginning of lines)
#
# Revision 1.15.2.3 2000/04/26 18:22:13 djs
# Rewrote type mapping code (now in types.py)
# Rewrote identifier handling code (now in id.py)
#
# Revision 1.15.2.2 2000/03/09 15:21:40 djs
# Better handling of internal compiler exceptions (eg attempts to use
# wide string types)
#
# Revision 1.15.2.1 2000/02/14 18:34:57 dpg1
# New omniidl merged in.
#
# Revision 1.15 2000/01/17 16:58:52 djs
# Marshalling code: exceptions (BAD_PARAM, MARSHAL) and bounded strings
#
# Revision 1.14 2000/01/11 12:02:34 djs
# More tidying up
#
# Revision 1.13 2000/01/07 20:31:18 djs
# Regression tests in CVSROOT/testsuite now pass for
# * no backend arguments
# * tie templates
# * flattened tie templates
# * TypeCode and Any generation
#
# Revision 1.12 1999/12/26 16:38:06 djs
# Support for bounded strings (specifically a bounds check raising
# CORBA::BAD_PARAM)
#
# Revision 1.11 1999/12/16 16:08:02 djs
# More TypeCode and Any fixes
#
# Revision 1.10 1999/12/15 12:11:54 djs
# Marshalling arrays of Anys fix
#
# Revision 1.9 1999/12/14 11:53:56 djs
# Support for CORBA::TypeCode and CORBA::Any
#
# Revision 1.8 1999/12/10 18:26:03 djs
# Added a utility function to order exceptions based on their names
#
# Revision 1.7 1999/11/29 19:26:59 djs
# Code tidied and moved around. Some redundant code eliminated.
#
# Revision 1.6 1999/11/29 15:26:04 djs
# Marshalling bugfixes.
#
# Revision 1.5 1999/11/26 18:52:06 djs
# Bugfixes and refinements
#
# Revision 1.4 1999/11/23 18:49:26 djs
# Lots of fixes, especially marshalling code
# Added todo list to keep track of issues
#
# Revision 1.3 1999/11/19 20:07:33 djs
# Bugfixes. Added utility functions for operations and attributes
#
# Revision 1.2 1999/11/17 20:37:09 djs
# General util functions
#
# Revision 1.1 1999/11/15 19:10:55 djs
# Added module for utility functions specific to generating skeletons
# Union skeletons working
#
import string
try:
# Python 3 does not have a built in reduce()
from functools import reduce
except ImportError:
pass
from omniidl import idlutil,idltype,idlast
from omniidl_be.cxx import util,types,id,ast,output,cxx
# From http://www-i3.informatik.rwth-aachen.de/funny/babbage.html:
#
# A hotly contested issue among language designers is the method for
# passing parameters to subfunctions. Some advocate "call by name," others
# prefer "call by value." Babbage uses a new method - "call by telephone."
# This is especially effective for long-distance parameter passing.
# Code for marshalling and unmarshalling various data types.
def marshall(to, environment, type, decl, argname, to_where,
exception = "BAD_PARAM"):
assert isinstance(type, types.Type)
d_type = type.deref()
# If this is an array of base types, the quick marshalling option is used.
# slice_cast is set to the casting required to cast the variable to a
# pointer to the beginning of the array. There are 3 possibilities:
# 1. The variable is a declarator, e.g. it is a member of a struct or a
# union. No casting is required. slice_cast = ""
# 2. The variable is not a declarator and its dimension is > 1,
# cast the variable to its array slice pointer.
# 3. Same as 2 but its dimension == 1, just cast the variable to a pointer
# to its base class (because the type's array slice may not be
# defined).
if decl:
assert isinstance(decl, idlast.Declarator)
dims = decl.sizes() + type.dims()
slice_cast = ""
else:
dims = type.dims()
if len(dims) != 1:
slice_cast = "(" + type.base(environment) + "_slice" + "*)"
else:
slice_cast = "(" + d_type.base(environment) + "*)"
if dims != []:
n_elements = reduce(lambda x,y:x*y, dims, 1)
array_marshal_helpers = {
idltype.tk_octet: ("omni::ALIGN_1",1),
idltype.tk_boolean: ("omni::ALIGN_1",1),
idltype.tk_short: ("omni::ALIGN_2",2),
idltype.tk_long: ("omni::ALIGN_4",4),
idltype.tk_ushort: ("omni::ALIGN_2",2),
idltype.tk_ulong: ("omni::ALIGN_4",4),
idltype.tk_float: ("omni::ALIGN_4",4),
idltype.tk_double: ("omni::ALIGN_8",8),
idltype.tk_longlong: ("omni::ALIGN_8",8),
idltype.tk_ulonglong: ("omni::ALIGN_8",8)
}
kind = d_type.type().kind()
if array_marshal_helpers.has_key(kind):
(alignment,elmsize) = array_marshal_helpers[kind]
if alignment != "omni::ALIGN_1":
if kind == idltype.tk_double:
to.out("""
#ifndef OMNI_MIXED_ENDIAN_DOUBLE""")
to.out("""\
if (! @where@.marshal_byte_swap()) {
@where@.put_octet_array((_CORBA_Octet*)(@slice_cast@@name@),@num@,@align@);
}
else """,
where = to_where,
name = argname,
slice_cast = slice_cast,
num = str(n_elements * elmsize),
align = alignment)
if kind == idltype.tk_double:
to.out("""\
#endif""")
# Do not return here.
# let the code below to deal with the else block.
else:
if kind == idltype.tk_boolean:
to.out("""
#if !defined(HAS_Cplusplus_Bool) || (SIZEOF_BOOL == 1)""")
to.out("@where@.put_octet_array((_CORBA_Octet*)(@slice_cast@@name@),@num@);",
where = to_where,
name = argname,
slice_cast = slice_cast,
num = str(n_elements))
if kind == idltype.tk_boolean:
to.out("""\
#else""")
else:
return
# No quick route, generate iteration loop
block = cxx.Block(to)
akind = d_type.type().kind()
# Valuetype chunked encoding needs to know array length before
# we marshal it item by item.
if array_marshal_helpers.has_key(akind):
to.out("""\
@where@.declareArrayLength(@align@, @num@);""",
where = to_where,
num = str(n_elements * elmsize),
align = alignment)
elif akind == idltype.tk_char:
to.out("""\
@where@.declareArrayLength(omni::ALIGN_1, @num@);""",
where = to_where,
num = str(n_elements))
elif akind == idltype.tk_longdouble:
to.out("""\
@where@.declareArrayLength(omni::ALIGN_8, @num@);""",
where = to_where,
num = str(n_elements * 16))
loop = cxx.For(to, dims)
indexing_string = loop.index()
element_name = argname + indexing_string
if dims != []:
type_name = d_type.base(environment)
if type_name == element_name:
type_name = d_type.base()
else:
type_name = type.base(environment)
if type_name == element_name:
type_name = type.base()
bounded = ""
kind = d_type.type().kind()
if d_type.interface():
type_name = string.replace(type_name,"_ptr","")
if isinstance(d_type.type().decl(),idlast.Forward):
# hack to denote an interface forward declaration
# kind is used to index the associative array below
kind = idltype.tk_objref * 1000
elif d_type.value() or d_type.valuebox():
if isinstance(d_type.type().decl(),idlast.ValueForward):
kind = idltype.tk_value * 1000
elif d_type.string() or d_type.wstring():
bounded = str(d_type.type().bound())
if not d_type.is_basic_data_types() and not d_type.enum():
type_cast = "(const " + type_name + "&) "
else:
type_cast = ""
special_marshal_functions = {
idltype.tk_boolean:
"@to_where@.marshalBoolean(@element_name@);",
idltype.tk_octet:
"@to_where@.marshalOctet(@element_name@);",
idltype.tk_char:
"@to_where@.marshalChar(@element_name@);",
idltype.tk_wchar:
"@to_where@.marshalWChar(@element_name@);",
idltype.tk_string:
"@to_where@.marshalString(@element_name@,@bounded@);",
idltype.tk_wstring:
"@to_where@.marshalWString(@element_name@,@bounded@);",
idltype.tk_objref:
"@type@::_marshalObjRef(@element_name@,@to_where@);",
idltype.tk_TypeCode:
"::CORBA::TypeCode::marshalTypeCode(@element_name@,@to_where@);",
idltype.tk_objref * 1000:
"@type@_Helper::marshalObjRef(@element_name@,@to_where@);",
idltype.tk_value:
"@type@::_NP_marshal(@element_name@,@to_where@);",
idltype.tk_value * 1000:
"@type@_Helper::marshal(@element_name@,@to_where@);",
idltype.tk_value_box:
"@type@::_NP_marshal(@element_name@,@to_where@);",
idltype.tk_abstract_interface:
"@type@::_marshalObjRef(@element_name@,@to_where@);",
idltype.tk_local_interface:
"@type@::_marshalObjRef(@element_name@,@to_where@);",
}
if special_marshal_functions.has_key(kind):
out_template = special_marshal_functions[kind]
else:
out_template = "@type_cast@@element_name@ >>= @to_where@;"
to.out(out_template,
to_where = to_where,
element_name = element_name,
bounded = bounded,
type = type_name,
type_cast = type_cast)
loop.end()
if dims != []:
block.end()
if kind == idltype.tk_boolean:
to.out("""\
#endif""")
def unmarshall(to, environment, type, decl, name, from_where):
assert isinstance(type, types.Type)
d_type = type.deref()
# If this is an array of base types, the quick marshalling option is used.
# slice_cast is set to the casting required to cast the variable to a
# pointer to the beginning of the array. There are 3 possibilities:
# 1. The variable is a declarator, e.g. it is a member of a struct or a
# union. No casting is required. slice_cast = ""
# 2. The variable is not a declarator and its dimension is > 1,
# cast the variable to its array slice pointer.
# 3. Same as 2 but its dimension == 1, just cast the variable to a pointer
# to its base class (because the type's array slice may not be
# defined).
if decl:
assert isinstance(decl, idlast.Declarator)
dims = decl.sizes() + type.dims()
slice_cast = ""
else:
dims = type.dims()
if len(dims) != 1:
slice_cast = "(" + type.base(environment) + "_slice" + "*)"
else:
slice_cast = "(" + d_type.base(environment) + "*)"
if dims != []:
n_elements = reduce(lambda x,y:x*y, dims, 1)
array_unmarshal_helpers = {
idltype.tk_octet: ("get_octet_array","(_CORBA_Octet*)"),
idltype.tk_boolean:("unmarshalArrayBoolean","(_CORBA_Boolean*)"),
idltype.tk_short: ("unmarshalArrayShort","(_CORBA_Short*)"),
idltype.tk_long: ("unmarshalArrayLong","(_CORBA_Long*)"),
idltype.tk_ushort: ("unmarshalArrayUShort","(_CORBA_UShort*)"),
idltype.tk_ulong: ("unmarshalArrayULong","(_CORBA_ULong*)"),
idltype.tk_float: ("unmarshalArrayFloat","(_CORBA_Float*)"),
idltype.tk_double: ("unmarshalArrayDouble","(_CORBA_Double*)"),
idltype.tk_longlong:("unmarshalArrayLongLong","(_CORBA_LongLong*)"),
idltype.tk_ulonglong:("unmarshalArrayULongLong","(_CORBA_ULongLong*)")
}
kind = d_type.type().kind()
if array_unmarshal_helpers.has_key(kind):
(helper,typecast) = array_unmarshal_helpers[kind]
to.out("@where@.@helper@(@typecast@(@slice_cast@@name@), @num@);",
helper = helper,
where = from_where, typecast = typecast,
name = name,
slice_cast = slice_cast,
num = str(n_elements))
return
# No quick route, generate iteration loop
block = cxx.Block(to)
loop = cxx.For(to, dims)
indexing_string = loop.index()
element_name = name + indexing_string
if dims != []:
type_name = d_type.base(environment)
if type_name == element_name:
type_name = d_type.base()
else:
type_name = type.base(environment)
if type_name == element_name:
type_name = type.base()
bounded = ""
kind = d_type.type().kind()
if d_type.interface():
type_name = string.replace(type_name,"_ptr","")
if isinstance(d_type.type().decl(),idlast.Forward):
# hack to denote an interface forward declaration
# kind is used to index the associative array below
kind = idltype.tk_objref * 1000
elif d_type.value() or d_type.valuebox():
if isinstance(d_type.type().decl(),idlast.ValueForward):
kind = idltype.tk_value * 1000
elif d_type.string() or d_type.wstring():
bounded = str(d_type.type().bound())
special_unmarshal_functions = {
idltype.tk_boolean:
"@element_name@ = @where@.unmarshalBoolean();",
idltype.tk_octet:
"@element_name@ = @where@.unmarshalOctet();",
idltype.tk_char:
"@element_name@ = @where@.unmarshalChar();",
idltype.tk_wchar:
"@element_name@ = @where@.unmarshalWChar();",
idltype.tk_string:
"@element_name@ = @where@.unmarshalString(@bounded@);",
idltype.tk_wstring:
"@element_name@ = @where@.unmarshalWString(@bounded@);",
idltype.tk_objref:
"@element_name@ = @type@::_unmarshalObjRef(@where@);",
idltype.tk_TypeCode:
"@element_name@ = ::CORBA::TypeCode::unmarshalTypeCode(@where@);",
idltype.tk_objref * 1000:
"@element_name@ = @type@_Helper::unmarshalObjRef(@where@);",
idltype.tk_value:
"@element_name@ = @type@::_NP_unmarshal(@where@);",
idltype.tk_value * 1000:
"@element_name@ = @type@_Helper::unmarshal(@where@);",
idltype.tk_value_box:
"@element_name@ = @type@::_NP_unmarshal(@where@);",
idltype.tk_abstract_interface:
"@element_name@ = @type@::_unmarshalObjRef(@where@);",
idltype.tk_local_interface:
"@element_name@ = @type@::_unmarshalObjRef(@where@);",
}
if special_unmarshal_functions.has_key(kind):
out_template = special_unmarshal_functions[kind]
else:
out_template = "(@type@&)@element_name@ <<= @where@;"
to.out(out_template,
type = type_name,
element_name = element_name,
where = from_where,
bounded = bounded)
loop.end()
if dims != []:
block.end()
def sort_exceptions(ex):
# sort the exceptions into lexicographical order
try:
return sorted(ex, key = lambda e: e.repoId())
except NameError:
def lexicographic(exception_a, exception_b):
name_a = exception_a.repoId()
name_b = exception_b.repoId()
return cmp(name_a, name_b)
raises = ex[:]
raises.sort(lexicographic)
return raises
|