1# -*- python -*-
2#                           Package   : omniidl
3# tie.py                    Created on: 1999/12/13
4#			    Author    : David Scott (djs)
5#
6#    Copyright (C) 2007-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 'tie' templates"""
27
28from omniidl import idlast, idlvisitor
29from omniidl_be.cxx import id, config, types, output, ast
30from omniidl_be.cxx.header import template
31
32import sys
33self = sys.modules[__name__]
34
35
36# Write a single tie template class called <name>, inheriting from <inherits>
37# and grab the operations from <node>
38def write_template(name, inherits, node, stream,
39                   Template = template.tie_template):
40    # build methods which bind the interface operations and attributes
41    # note that this includes inherited callables since tie
42    # templates are outside the normal inheritance structure
43    where = output.StringStream()
44
45    # defined_so_far contains keys corresponding to method names which
46    # have been defined already (and which should not be included twice)
47    def buildCallables(interface, where, continuation, defined_so_far = {}):
48        interface = ast.remove_ast_typedefs(interface)
49
50        callables = interface.callables()
51        operations = [x for x in callables if isinstance(x, idlast.Operation)]
52        for operation in operations:
53            returnType = types.Type(operation.returnType())
54            identifier = operation.identifier()
55            if (identifier in defined_so_far):
56                # don't repeat it
57                continue
58            defined_so_far[identifier] = 1
59
60            parameters = operation.parameters()
61            has_return_value = not returnType.void()
62            # FIXME: return types are fully scoped but argument types
63            # arent?
64            returnType_name = returnType.op(types.RET)
65
66            operation_name = id.mapID(identifier)
67
68            signature = []
69            call = []
70
71            for parameter in parameters:
72                paramType = types.Type(parameter.paramType())
73                # Need to call the _impl operation not the _objref operation
74                param_type_name = paramType.op(types.direction(parameter),
75                                               use_out = 0)
76                param_id = id.mapID(parameter.identifier())
77                signature.append(param_type_name + " " + param_id)
78                call.append(param_id)
79
80            # deal with call contextx
81            if operation.contexts() != []:
82                signature.append("::CORBA::Context_ptr _ctxt")
83                call.append("_ctxt")
84
85            if has_return_value:
86                return_str = "return "
87            else:
88                return_str = ""
89
90            where.out("""\
91@return_type_name@ @operation_name@(@signature@) { @return_str@pd_obj->@operation_name@(@call@); }""", return_type_name = returnType_name,
92                      operation_name = operation_name,
93                      return_str = return_str,
94                      signature = ", ".join(signature),
95                      call = ", ".join(call))
96
97        attributes = [x for x in callables if isinstance(x, idlast.Attribute)]
98        for attribute in attributes:
99            identifiers = attribute.identifiers()
100            attrType = types.Type(attribute.attrType())
101
102            attrType_name_RET = attrType.op(types.RET)
103            attrType_name_IN = attrType.op(types.IN)
104
105            for identifier in identifiers:
106                if identifier in defined_so_far:
107                    # don't repeat it
108                    continue
109                defined_so_far[identifier] = 1
110
111                ident = id.mapID(identifier)
112                where.out("""\
113@attr_type_ret_name@ @attribute_name@() { return pd_obj->@attribute_name@(); }""", attr_type_ret_name = attrType_name_RET,
114                          attribute_name = ident)
115
116                if not attribute.readonly():
117                    where.out("""\
118void @attribute_name@(@attr_type_in_name@ _value) { pd_obj->@attribute_name@(_value); }""", attribute_name = ident,
119                              attr_type_in_name = attrType_name_IN)
120        # do the recursive bit
121        for i in interface.inherits():
122            i = i.fullDecl()
123            continuation(i, where, continuation, defined_so_far)
124
125        # done
126        return
127
128    buildCallables(node, where, buildCallables)
129
130    stream.out(Template,
131               tie_name = name,
132               inherits = inherits,
133               callables = str(where))
134    return
135
136
137# Unflattened BOA tie templates are built in a block out of line.
138# IDL name       template name
139#  ::A             ::_tie_A
140#  ::B             ::_tie_B
141#  ::M::C          ::_tie_M::C
142
143class BOATieTemplates(idlvisitor.AstVisitor):
144    def __init__(self, stream):
145        self.stream = stream
146
147    def visitAST(self, node):
148        for d in node.declarations():
149            if ast.shouldGenerateCodeForDecl(d):
150                d.accept(self)
151
152    def visitModule(self, node):
153        name = id.Name(node.scopedName())
154
155        self.stream.out(template.module_begin,
156                   name = "_tie_" + name.simple())
157        self.stream.inc_indent()
158
159        for d in node.definitions(): d.accept(self)
160
161        self.stream.dec_indent()
162        self.stream.out(template.module_end)
163
164
165    def visitInterface(self, node):
166        name = id.Name(node.scopedName())
167
168        tie_name = name.simple()
169        if len(node.scopedName()) == 1: tie_name = "_tie_" + tie_name
170
171        sk_name = name.prefix("_sk_")
172
173        write_template(tie_name, sk_name.fullyQualify(), node, self.stream,
174                       Template = template.tie_template_old)
175
176
177# Flat Tie Templates are all (by definition) in the global scope,
178# so can combine POA and BOA code into one
179class FlatTieTemplates(idlvisitor.AstVisitor):
180    def __init__(self, stream):
181        self.stream = stream
182
183    def visitAST(self, node):
184        for d in node.declarations():
185            if ast.shouldGenerateCodeForDecl(d):
186                d.accept(self)
187
188    def visitModule(self, node):
189        for d in node.definitions():
190            d.accept(self)
191
192    def visitInterface(self, node):
193        self.generate_POA_tie(node)
194        if config.state['BOA Skeletons']:
195            self.generate_BOA_tie(node)
196
197    def generate_BOA_tie(self, node):
198        name = id.Name(node.scopedName())
199        tie_name = "_tie_" + "_".join(name.fullName())
200        sk_name = name.prefix("_sk_")
201
202        write_template(tie_name, sk_name.fullyQualify(), node, self.stream,
203                       Template = template.tie_template_old)
204
205    def generate_POA_tie(self, node):
206        name = id.Name(node.scopedName())
207        tie_name = "POA_" + "_".join(name.fullName()) + "_tie"
208        poa_name = "POA_" + name.fullyQualify()
209
210        write_template(tie_name, poa_name, node, self.stream)
211