1"""Type classes and a modest collection of standard types."""
2
3
4from bgenOutput import *
5
6
7class Type:
8
9    """Define the various things you can do with a C type.
10
11    Most methods are intended to be extended or overridden.
12    """
13
14    def __init__(self, typeName, fmt):
15        """Call with the C name and getargs format for the type.
16
17        Example: int = Type("int", "i")
18        """
19        self.typeName = typeName
20        self.fmt = fmt
21
22    def declare(self, name, reference=False):
23        """Declare a variable of the type with a given name.
24
25        Example: int.declare('spam') prints "int spam;"
26        """
27        for decl in self.getArgDeclarations(name, reference):
28            Output("%s;", decl)
29        for decl in self.getAuxDeclarations(name):
30            Output("%s;", decl)
31
32    def getArgDeclarations(self, name, reference=False, constmode=False, outmode=False):
33        """Return the main part of the declarations for this type: the items
34        that will be passed as arguments in the C/C++ function call."""
35        if reference:
36            ref = "&"
37        else:
38            ref = ""
39        if constmode:
40            const = "const "
41        else:
42            const = ""
43        if outmode:
44            out = "*"
45        else:
46            out = ""
47        return ["%s%s%s%s %s" % (const, self.typeName, ref, out, name)]
48
49    def getAuxDeclarations(self, name):
50        """Return any auxiliary declarations needed for implementing this
51        type, such as helper variables used to hold sizes, etc. These declarations
52        are not part of the C/C++ function call interface."""
53        return []
54
55    def getargs(self):
56        return self.getargsFormat(), self.getargsArgs()
57
58    def getargsFormat(self):
59        """Return the format for this type for use with PyArg_Parse().
60
61        Example: int.getargsFormat() returns the string "i".
62        (getargs is a very old name for PyArg_Parse, hence the name of this method).
63        """
64        return self.fmt
65
66    def getargsArgs(self, name):
67        """Return an argument for use with PyArg_Parse().
68
69        Example: int.getargsArgs("spam") returns the string "&spam".
70        """
71        return "&" + name
72
73    def getargsPreCheck(self, name):
74        """Perform any actions needed before calling getargs().
75
76        This could include declaring temporary variables and such.
77        """
78
79    def getargsCheck(self, name):
80        """Perform any needed post-[new]getargs() checks.
81
82        This is type-dependent; the default does not check for errors.
83        An example would be a check for a maximum string length, or it
84        could do post-getargs() copying or conversion."""
85
86    def passInput(self, name):
87        """Return an argument for passing a variable into a call.
88
89        Example: int.passInput("spam") returns the string "spam".
90        """
91        return name
92
93    def passOutput(self, name):
94        """Return an argument for returning a variable out of a call.
95
96        Example: int.passOutput("spam") returns the string "&spam".
97        """
98        return "&" + name
99
100    def passReference(self, name):
101        """Return an argument for C++ pass-by-reference.
102        Default is to call passInput().
103        """
104        return self.passInput(name)
105
106    def errorCheck(self, name):
107        """Check for an error returned in the variable.
108
109        This is type-dependent; the default does not check for errors.
110        An example would be a check for a NULL pointer.
111        If an error is found, the generated routine should
112        raise an exception and return NULL.
113
114        XXX There should be a way to add error clean-up code.
115        """
116        Output("/* XXX no err check for %s %s */", self.typeName, name)
117
118    def mkvalue(self):
119        return self.mkvalueFormat(), self.mkvalueArgs()
120
121    def mkvalueFormat(self):
122        """Return the format for this type for use with Py_BuildValue().
123
124        This is normally the same as getargsFormat() but it is
125        a separate function to allow future divergence.
126        (mkvalue is a very old name for Py_BuildValue, hence the name of this
127        method).
128        """
129        return self.getargsFormat()
130
131    def mkvalueArgs(self, name):
132        """Return an argument for use with Py_BuildValue().
133
134        Example: int.mkvalueArgs("spam") returns the string "spam".
135        """
136        return name
137
138    def mkvaluePreCheck(self, name):
139        """Perform any actions needed before calling mkvalue().
140
141        This could include declaring temporary variables and such.
142        """
143
144    def cleanup(self, name):
145        """Clean up if necessary.
146
147        This is normally empty; it may deallocate buffers etc.
148        """
149        pass
150
151class ByAddressType(Type):
152    "Simple type that is also passed by address for input"
153
154    def passInput(self, name):
155        return "&%s" % name
156
157
158
159# Sometimes it's useful to define a type that's only usable as input or output parameter
160
161class InputOnlyMixIn:
162
163    "Mix-in class to boobytrap passOutput"
164
165    def passOutput(self, name):
166        raise RuntimeError, "Type '%s' can only be used for input parameters" % self.typeName
167
168class InputOnlyType(InputOnlyMixIn, Type):
169
170    "Same as Type, but only usable for input parameters -- passOutput is boobytrapped"
171
172class OutputOnlyMixIn:
173
174    "Mix-in class to boobytrap passInput"
175
176    def passInput(self, name):
177        raise RuntimeError, "Type '%s' can only be used for output parameters" % self.typeName
178
179class OutputOnlyType(OutputOnlyMixIn, Type):
180
181    "Same as Type, but only usable for output parameters -- passInput is boobytrapped"
182
183
184# A modest collection of standard C types.
185void = None
186char = Type("char", "c")
187short = Type("short", "h")
188unsigned_short = Type("unsigned short", "H")
189int = Type("int", "i")
190long = Type("long", "l")
191unsigned_long = Type("unsigned long", "l")
192float = Type("float", "f")
193double = Type("double", "d")
194
195
196# The most common use of character pointers is a null-terminated string.
197# For input, this is easy.  For output, and for other uses of char *,
198# see the module bgenBuffer.
199stringptr = InputOnlyType("char*", "s")
200unicodestringptr = InputOnlyType("wchar_t *", "u")
201
202
203# Some Python related types.
204objectptr = Type("PyObject*", "O")
205stringobjectptr = Type("PyStringObject*", "S")
206# Etc.
207
208
209class FakeType(InputOnlyType):
210
211    """A type that is not represented in the Python version of the interface.
212
213    Instantiate with a value to pass in the call.
214    """
215
216    def __init__(self, substitute):
217        self.substitute = substitute
218        self.typeName = None    # Don't show this argument in __doc__ string
219
220    def getArgDeclarations(self, name, reference=False, constmode=False, outmode=False):
221        return []
222
223    def getAuxDeclarations(self, name, reference=False):
224        return []
225
226    def getargsFormat(self):
227        return ""
228
229    def getargsArgs(self, name):
230        return None
231
232    def passInput(self, name):
233        return self.substitute
234
235
236class OpaqueType(Type):
237
238    """A type represented by an opaque object type, always passed by address.
239
240    Instantiate with the type name and the names of the new and convert procs.
241    If fewer than three arguments are passed, the second argument is used
242    to derive the new and convert procs by appending _New and _Convert; it
243    defaults to the first argument.
244    """
245
246    def __init__(self, name, arg = None, extra = None):
247        self.typeName = name
248        if extra is None:
249             # Two arguments (name, usetype) or one (name)
250            arg = arg or name
251            self.new = arg + '_New'
252            self.convert = arg + '_Convert'
253        else:
254            # Three arguments (name, new, convert)
255            self.new = arg
256            self.convert = extra
257
258    def getargsFormat(self):
259        return "O&"
260
261    def getargsArgs(self, name):
262        return "%s, &%s" % (self.convert, name)
263
264    def passInput(self, name):
265        return "&%s" % name
266
267    def mkvalueFormat(self):
268        return "O&"
269
270    def mkvalueArgs(self, name):
271        return "%s, &%s" % (self.new, name)
272
273
274class OpaqueByValueType(OpaqueType):
275
276    """A type represented by an opaque object type, on input passed BY VALUE.
277
278    Instantiate with the type name, and optionally an object type name whose
279    New/Convert functions will be used.
280    """
281
282    def passInput(self, name):
283        return name
284
285    def mkvalueArgs(self, name):
286        return "%s, %s" % (self.new, name)
287
288class OpaqueByRefType(OpaqueType):
289    """An opaque object type, passed by reference.
290
291    Instantiate with the type name, and optionally an object type name whose
292    New/Convert functions will be used.
293    """
294
295    def passInput(self, name):
296        return name
297
298#    def passOutput(self, name):
299#        return name
300
301    def mkvalueFormat(self):
302        return "O"
303
304    def mkvalueArgs(self, name):
305        return "%s(%s)" % (self.new, name)
306
307class OpaqueByValueStructType(OpaqueByValueType):
308    """Similar to OpaqueByValueType, but we also pass this to mkvalue by
309    address, in stead of by value.
310    """
311
312    def mkvalueArgs(self, name):
313        return "%s, &%s" % (self.new, name)
314
315
316class OpaqueArrayType(OpaqueByValueType):
317
318    """A type represented by an opaque object type, with ARRAY passing semantics.
319
320    Instantiate with the type name, and optional an object type name whose
321    New/Convert functions will be used.
322    """
323
324    def getargsArgs(self, name):
325        return "%s, %s" % (self.convert, name)
326
327    def passOutput(self, name):
328        return name
329