1#!/usr/bin/env python
2
3"""
4Various formatting classes for Ada code
5"""
6
7import sys
8import re
9import copy
10from collections import namedtuple, defaultdict
11
12# A lot of subprograms below take a "lang" parameter, which indicates how
13# values should be converted:
14#
15#     LANG should be one of:
16#        "ada":  the value of the parameter is read from an Ada
17#           value (as subprogram whose code is Ada) and passed to a
18#           similar subprogram. No conversion needed.
19#        "ada->c": all Ada values will be converted to their C equivalent,
20#           since the target subprogram's code is written in C.
21#        "c->ada": case of C callbacks: the value is passed from C to
22#           an Ada subprogram in the user application.
23#
24#     As an example, here is what the types for a list of strings
25#     would look like in all languages:
26#
27#           "ada"    -> String_List
28#           "c->ada" -> chars_ptr_array_access (no bounds given by C)
29#           "ada->c" -> chars_ptr_array (bounds will be ignored anyway,
30#                         and it is simpler to pass this type).
31
32
33class CType(object):
34
35    """Describes the types in the various cases where they can be used.
36
37       A type applies either to an Ada subprogram written in Ada, or to an
38       Ada subprogram implemented via a pragma Import. The latter case is
39       abbreviated to a "c" subprogram below.
40
41       For returned values, various pieces of information are needed:
42              (adatype, ctype, converter, tmpvars=[])
43       They are used as:
44              function ... (...) return adatype is
45                  function ... (...) return ctype;
46                  pragma Import (C, ..., "...");
47                  Tmp : ctype;
48                  tmpvars;
49              begin
50                  ...;   --  pre-call code
51                  Tmp := ... (...);
52                  ...;   --  post-call code
53                  return <converter % Tmp>
54              end;
55       In the example above, "Tmp" is only created if there is some post-call
56       code, otherwise we avoid the temporary variable.
57       The variable "Tmp" is automatically added, and does not need to
58       be specified manually in tmpvars.
59
60       if converted contains the string "%(tmp)s", then we always use a
61       temporary variable of type adatype. This is used for instance when the
62       variable is initialized through a procedure call rather than a function
63       call.
64              function ... (...) return adatype is
65                  function ... (...) return ctype;
66                  pragma Import (C, ..., "...")
67                  Tmp_Result : adatype;
68                  tmpvars;
69              begin
70                  ...   --  pre-call code
71                  convert % {"var":..., "tmp":"Tmp_Result"};  -- proc call
72                  ...   --  post-call code
73                  return Tmp_Result;
74              end;
75       The variable "Tmp_Result" is automatically added, and does not need to
76       be specified manually in tmpvars.
77
78       Converter will contain a single %s which will be replaced by the
79       name of the temporary variable that holds the result of the call
80       to the function.
81    """
82
83    def __init__(self, ada, property):
84        self.set_ada_name(ada)
85        self.property = property
86        self.default_record_field_value = None
87
88        self.is_ptr = False
89
90        self.cleanup = None
91        # If set, a tmp variable is created to hold the result of convert
92        # during the call, and is then free by calling this cleanup. Use
93        # "%s" as the name of the variable.
94
95        self.isArray = False
96
97        # In some cases, Ada provides a special value for a parameter that
98        # indicates that NULL should be passed to C. Such a test is only done
99        # when allow_none is True. val_or_null is then a function in charge
100        # of converting the value to a System.Address unless it is equal to
101        # a specific null value.
102
103        self.allow_none = False
104        self.val_or_null = None
105
106        # If True, the value returned from C must be freed by the caller
107
108        self.transfer_ownership = False
109
110    def set_ada_name(self, ada):
111        self.ada = ada       # Fully qualified Ada type
112        self.param = ada     # type as parameter
113        self.cparam = ada    # type for Ada subprograms binding to C
114
115    def convert_from_c(self):
116        """How to convert the value returned from C to Ada.
117           This function returns a tuple:
118              [0] = name of the Ada type
119              [1] = name of the C type
120              [2] = Conversion from C type to Ada type. The value is read
121                    from "%(var)s". It can also use "%(tmp)s" if a temporary
122                    variable is needed.
123              [3] = List of needed temporary variables (except for the one
124                    corresponding to "%(tmp)s".
125              [4] = Name of the C type, for "out" parameters. Often same as [1]
126              [5] = Convert from [4] to the Ada type. Often same as [2]
127        """
128        return (self.param, self.cparam, "%(var)s", [], self.cparam, "%(var)s")
129
130    def convert_from_c_add_with(self, pkg, specs=False):
131        """Add the "with" statements needed to do the conversion stated
132           in convert_from_c().
133        """
134        pass
135
136    def convert_to_c(self, pkg=None):
137        """How to convert from Ada parameter to C parameter. If it uses %(tmp)s,
138           we assume the converter sets the value of the temporary variable
139           itself.
140           It can also use %(var)s which will be substituted by the name of the
141           parameter.
142           Otherwise, it is used as " Tmp := <convert>".
143           It might be necessary to also override add_with() to add the
144           necessary with statements.
145        """
146
147        if self.allow_none and self.val_or_null:
148            self.cparam = "System.Address"
149            return "%s (%%(var)s'Address)" % self.val_or_null
150        else:
151            return "%(var)s"
152
153    def direct_c_map(self):
154        """Whether the parameter can be passed as is to C"""
155        return self.convert_to_c(pkg=None) == "%(var)s"
156
157    def as_property(self):
158        """The type to use for the property"""
159        return self.property
160
161    def as_return(self, pkg=None):
162        """See CType documentation for a description of the returned tuple"""
163
164        returns = self.convert_from_c()
165
166        if returns and pkg:
167            # Avoid full dotted notation when inside the package itself
168            return (returns[0].replace("%s." % pkg.name, ""),
169                    returns[1].replace("%s." % pkg.name, ""),
170                    returns[2],
171                    returns[3],
172                    returns[4],
173                    returns[5])
174        else:
175            return returns
176
177    def record_field_type(self, pkg=None):
178        """The type to use when self is used in a record.
179           [pkg] should be the current package, to avoid fully qualified name
180           that reference that package.
181        """
182        return self.as_c_param(pkg=pkg)
183
184    def as_ada_param(self, pkg):
185        """Converts self to a description for an Ada parameter to a
186           subprogram.
187           `pkg` is the package in which we insert the name. It is used to
188           avoid qualified name when in the same package
189        """
190        # Do not fully qualify within the current package
191        p = self.ada[:self.ada.rfind(".")]
192        return self.param.replace("%s." % pkg.name, "")
193
194    def as_c_param(self, pkg=None):
195        """Returns the C type (as a parameter to a subprogram that imports
196           a C function)
197        """
198        if pkg:
199            return self.cparam.replace("%s." % pkg.name, "")
200        else:
201            return self.cparam
202
203    def as_call(
204            self, name, pkg, wrapper="%s", lang="ada", mode="in", value=None,
205            is_temporary_variable=True):
206        """'name' represents a parameter of type 'self'.
207           'pkg' is the Package instance in which the call occurs.
208           'wrapper' is used in the call itself, and %s is replaced by the
209              name of the variable (or the temporary variable).
210           'mode' is the mode for the Ada subprogram, and is automatically
211              converted when generating a subprogram as a direct C import.
212           :param is_temporary_variable: should be true if the corresponding
213              variable is a variable local to the subprogram, as opposed to a
214              parameter. In this case, we can sometimes avoid creating a second
215              temporary variable, thus increasing efficiency.
216           Returns an instance of VariableCall.
217           See comments at the beginning of this package for valid LANG values
218        """
219        assert lang in ("ada", "c->ada", "ada->c")
220        assert mode in ("in", "out", "access", "not null access",
221                        "in out"), "Incorrect mode: %s" % mode
222
223        if lang == "ada":
224            return VariableCall(
225                call=wrapper % name, precall='', postcall='', tmpvars=[])
226
227        elif lang == "ada->c":
228            returns = self.convert_from_c()
229            ret = returns and returns[2]
230
231            additional_tmp_vars = [] if not returns else returns[3]
232
233            # An "out" parameter for an enumeration requires a temporary
234            # variable: Internal(Enum'Pos(Param)) is invalid
235            # Unless we are already using a temporary variable.
236
237            if (ret
238                    and ret != "%(var)s"
239                    and mode != "in"
240                    and not is_temporary_variable):
241
242                tmp = "Tmp_%s" % name
243
244                if mode in ("out", "access"):
245                    tmpvars = [Local_Var(
246                        name=tmp, type=returns[4], aliased=True)]
247                else:
248                    tmpvars = [
249                        Local_Var(name=tmp, type=returns[4], aliased=True,
250                                  default=self.convert_to_c(pkg=pkg) % {
251                            "var": name})]
252
253                if "%(tmp)s" in ret:
254                    tmp2 = "Tmp2_%s" % name
255                    tmpvars += [Local_Var(name=tmp2, type=returns[4])]
256                    postcall = "%s; %s := %s;" % (
257                        returns[5] % {"var": tmp, "tmp": tmp2},
258                        name,
259                        tmp2)
260                else:
261                    postcall = "%s := %s;" % (
262                        name,
263                        returns[5] % {"var": tmp})
264
265                call = VariableCall(
266                    call=wrapper % tmp,
267                    precall="",
268                    postcall=postcall,
269                    tmpvars=tmpvars + additional_tmp_vars)
270
271            elif "%(tmp)" in self.convert_to_c(pkg=pkg):
272                # The conversion sets the temporary variable itself
273                tmp = "Tmp_%s" % name
274                call = VariableCall(
275                    call=wrapper % tmp,
276                    precall=self.convert_to_c(pkg=pkg) % {
277                        "var": name, "tmp": tmp},
278                    postcall=self.cleanup % tmp,
279                    tmpvars=[Local_Var(name=tmp, type=self.cparam)] + [])
280
281            elif self.cleanup:
282                tmp = "Tmp_%s" % name
283                conv = self.convert_to_c(pkg=pkg) % {"var": name}
284
285                # Initialize the temporary variable with a default value, in
286                # case it is an unconstrained type (a chars_ptr_array for
287                # instance)
288                call = VariableCall(
289                    call=wrapper % tmp,
290                    precall='',
291                    postcall=self.cleanup % tmp,
292                    tmpvars=[Local_Var(
293                        name=tmp, type=AdaType(self.cparam), default=conv)])
294
295            else:
296                conv = self.convert_to_c(pkg=pkg) % {"var": name}
297                call = VariableCall(
298                    call=wrapper % conv, precall='', postcall="", tmpvars=[])
299
300            return call
301
302        elif lang == "c->ada":
303            ret = self.convert_from_c()
304            self.convert_from_c_add_with(pkg=pkg)
305
306            # Do we need a temporary variable ?
307            # An "out" parameter for an enumeration requires a temporary
308            # variable: Internal(Enum'Pos (Param)) is invalid
309
310            ret_convert = ret and ret[2]
311
312            if ret_convert and ret_convert != "%(var)s" and mode != "in":
313                tmp = "Tmp_%s" % name
314                tmpvars = [Local_Var(name=tmp, type=self.ada)] + ret[3]
315
316                if "%(tmp)s" in ret_convert:
317                    tmp2 = "Tmp2_%s" % name
318                    tmpvars += [Local_Var(name=tmp2, type=self.cparam)]
319                    postcall = "%s; %s := %s;" % (
320                        ret_convert % {"var": tmp, "tmp": tmp2},
321                        name,
322                        tmp2)
323                else:
324                    postcall = "%s := %s;" % (
325                        name,
326                        self.convert_to_c(pkg=pkg) % {"var": tmp})
327
328                return VariableCall(
329                    call=wrapper % tmp,
330                    precall="",
331                    postcall=postcall,
332                    tmpvars=tmpvars)
333
334            else:
335                return VariableCall(
336                    call=wrapper % (ret[2] % {"var": name}),
337                    precall='', postcall='', tmpvars=ret[3])
338
339    def add_with(self, pkg=None, specs=False):
340        """Add required withs for this type"""
341        if pkg:
342            pkg.add_with(package_name(self.ada))
343
344        if pkg and self.allow_none and self.val_or_null:
345            base = self.val_or_null
346            pkg.add_with(package_name(base), specs=specs)
347
348    def copy(self):
349        """Return a copy of self, possibly modifying some properties."""
350        return copy.deepcopy(self)
351
352
353class Enum(CType):
354
355    def __init__(self, ada, property=None):
356        base = ada[ada.rfind(".") + 1:] or ada
357        if property is None:
358            CType.__init__(self, ada, "Gtk.Enums.Property_%s" % base)
359        else:
360            CType.__init__(self, ada, property)
361
362        if self.ada.lower() == "boolean":
363            self.cparam = "Glib.Gboolean"
364        else:
365            # Do not convert enumerations to integers. We want to pass the
366            # associated literal in case the enumeration in C does not start
367            # at 0, or as holes in the series.
368            self.cparam = self.ada
369
370    def convert_from_c(self):
371        if self.ada.lower() == "boolean":
372            if self.ada == "Boolean":
373                # Do not use Boolean'Val for more flexibility, in case C
374                # returns another value than 0 and 1 (as is the case for
375                # gtk_status_icon_position_menu on OSX for instance).
376                conv = "%(var)s /= 0"
377            else:
378                conv = "%s'Val (%%(var)s)" % self.ada
379            return (self.param, self.cparam, conv, [],
380
381                    # for out parameters
382                    self.cparam, conv)
383        else:
384            return super(Enum, self).convert_from_c()
385
386    def convert_to_c(self, pkg=None):
387        if self.ada.lower() == "boolean":
388            return "%s'Pos (%%(var)s)" % self.ada
389        else:
390            return super(Enum, self).convert_to_c(pkg=pkg)
391
392    def record_field_type(self, pkg=None):
393        if pkg:
394            return self.ada.replace("%s." % pkg.name, "")
395        else:
396            return self.ada
397
398    @staticmethod
399    def register_ada_decl(pkg, ctype, ada=None):
400        """Register an enumeration type.
401        :param pkg: is the name of the current package in which the enumeration
402        will be defined.
403        """
404
405        # Compute the Ada name automatically if needed.
406        if not ada:
407            ada = naming.type(name="", cname=ctype).ada
408
409        full_name = "%s.%s" % (pkg, ada)
410        t = Enum(full_name, "%s.Property_%s" % (pkg, ada))
411        naming.add_type_exception(cname=ctype, type=t)
412
413        # Add the special cases for properties that GIR file use
414        t = ctype.replace("Pango", "Pango.").replace("Gdk", "Gdk.")
415        naming.girname_to_ctype[t] = ctype
416
417
418class GObject(CType):
419
420    def __init__(self, ada, userecord=True, allow_none=False, classwide=False):
421        CType.__init__(self, ada, "Glib.Properties.Property_Object")
422        self.cparam = "System.Address"
423        self.is_ptr = False
424        self.classwide = classwide  # Parameter should include "'Class"
425        self.userecord = userecord  # Parameter should be "access .._Record"
426        self.allow_none = allow_none
427
428    def convert_from_c(self):
429        stub = "Stub_%s" % (base_name(self.ada), )
430
431        if self.ada == "Glib.Object.GObject":
432            conv = "Get_User_Data (%%(var)s, %s)" % stub
433        else:
434            conv = "%s (Get_User_Data (%%(var)s, %s))" % (self.ada, stub)
435
436        return (self.param,
437                self.cparam,
438                conv,
439                [Local_Var(
440                    stub, AdaType("%s_Record" % self.ada, in_spec=False))],
441
442                # for out parameters
443                self.cparam, conv)
444
445    def convert_to_c(self, pkg=None):
446        if self.allow_none:
447            return "Get_Object_Or_Null (GObject (%(var)s))"
448        else:
449            return "Get_Object (%(var)s)"
450
451    def as_ada_param(self, pkg):
452        if self.userecord:
453            prefix = "" if self.allow_none else "not null "
454
455            if self.classwide:
456                self.param = "%saccess %s_Record'Class" % (prefix, self.ada)
457            else:
458                self.param = "%saccess %s_Record" % (prefix, self.ada)
459
460        return super(GObject, self).as_ada_param(pkg)
461
462    def copy(self):
463        result = CType.copy(self)
464        return result
465
466
467class Tagged(GObject):
468
469    """Tagged types that map C objects, but do not derive from GObject"""
470
471    def convert_from_c(self):
472        return (self.param, self.cparam, "From_Object (%(var)s)", [],
473
474                # for out parameters
475                self.cparam, "From_Object (%(var)s)")
476
477    def convert_to_c(self, pkg=None):
478        return "Get_Object (%(var)s)"
479
480    def as_ada_param(self, pkg):
481        # Make sure to bind as a CType here, not as a GOBject
482        return CType.as_ada_param(self, pkg)
483
484
485class UTF8(CType):
486
487    def __init__(self):
488        CType.__init__(self, "UTF8_String", "Glib.Properties.Property_String")
489        self.cparam = "Interfaces.C.Strings.chars_ptr"
490        self.cleanup = "Free (%s);"
491
492    def convert_from_c(self):
493        conv = "Gtkada.Bindings.Value_Allowing_Null (%(var)s)"
494
495        if self.transfer_ownership:
496            conv = "Gtkada.Bindings.Value_And_Free (%(var)s)"
497
498        return (self.param, self.cparam, conv, [],
499
500                # for out parameters
501                self.cparam, conv)
502
503    def convert_from_c_add_with(self, pkg, specs=False):
504        if pkg:
505            pkg.add_with("Gtkada.Bindings", specs=specs)
506
507    def convert_to_c(self, pkg=None):
508        if self.allow_none:
509            return 'if %(var)s = "" then %(tmp)s :=' \
510                + ' Interfaces.C.Strings.Null_Ptr; else'\
511                + ' %(tmp)s := New_String (%(var)s); end if;'
512        else:
513            return "New_String (%(var)s)"
514
515    def add_with(self, pkg, specs=False):
516        super(UTF8, self).add_with(pkg)
517        if pkg:
518            pkg.add_with("Interfaces.C.Strings", specs=specs,
519                         might_be_unused=True)
520
521
522class SignalName(UTF8):
523    """
524    A special kind of utf8 used for signal names
525    """
526    def __init__(self):
527        super(SignalName, self).__init__()
528        self.set_ada_name("Glib.Signal_Name")
529        self.cparam = "Interfaces.C.Strings.chars_ptr"
530
531    def convert_to_c(self, pkg=None):
532        return "New_String (String (%(var)s))"
533
534
535class UTF8_List(CType):
536
537    def __init__(self):
538        CType.__init__(self, "GNAT.Strings.String_List", "")
539        self.cparam = "Interfaces.C.Strings.chars_ptr_array"
540        self.cleanup = "GtkAda.Types.Free (%s);"
541
542    def convert_from_c(self):
543        # Use a temporary variable to store the result of To_String_List,
544        # because in some cases the result will need to be freed. For instance,
545        # when a callback from C receives a list of strings as
546        # chars_ptr_array_access, we create a temporary String_List to call the
547        # Ada callback, and then need to free the temporary String_List.
548
549        conv = "To_String_List (%(var)s.all)"
550
551        if self.transfer_ownership:
552            conv = "To_String_List_And_Free (%(var)s)"
553
554        return (self.param, "chars_ptr_array_access", conv, [],
555
556                # for out parameters
557                "chars_ptr_array_access", conv)
558
559    def record_field_type(self, pkg=None):
560        return "Interfaces.C.Strings.char_array_access"
561
562    def convert_to_c(self, pkg=None):
563        if pkg:
564            pkg.add_with("GtkAda.Types", specs=False)
565        return "From_String_List (%(var)s)"
566
567    def add_with(self, pkg=None, specs=False):
568        super(UTF8_List, self).add_with(pkg=pkg)
569        if pkg:
570            pkg.add_with("GNAT.Strings", specs=True)
571            pkg.add_with("Interfaces.C.Strings", specs=specs)
572            pkg.add_with("Gtkada.Bindings", specs=specs, might_be_unused=True)
573
574
575class Record(CType):
576
577    def __init__(self, ada, property=None, val_or_null=None):
578        """
579           :param val_or_null: if specified, and the null constant is passed
580             as a parameter, then System.Null_Address is passed to C. If
581             unspecified, any value passed by the user is given as is to C.
582        """
583
584        if property is None:
585            CType.__init__(self, ada, "Glib.Properties.Property_Boxed")
586        else:
587            CType.__init__(self, ada, property)
588
589        self.val_or_null = val_or_null
590
591        # Do not change self.cparam: when passing a read-only parameter to
592        # C, GNAT will automatically pass the address of the record
593        self.cparam = ada
594
595    def convert_from_c(self):
596        conv = "%(var)s.all"  # convert C -> Ada,
597        if self.transfer_ownership:
598            conv = "From_Object_Free (%(var)s)"
599
600        return (self.ada,
601                "access %s" % self.ada,
602                conv,
603                [],
604
605                # for out parameters
606                self.ada, "%(var)s")
607
608    def convert_to_c(self, pkg=None):
609        if self.allow_none and self.val_or_null:
610            self.cparam = "System.Address"
611            return "%s (%%(var)s'Address)" % self.val_or_null
612        else:
613            return "%(var)s"
614
615    @staticmethod
616    def register_ada_record(pkg, ctype, ada=None):
617        """Register a <record> type.
618        [pkg] is the name of the current package in which the enumeration
619        will be defined.
620        """
621
622        adaname = base_name(ada or naming.type(name="", cname=ctype).ada)
623        full_name = "%s.%s" % (pkg, adaname)
624        t = Record(full_name)
625        naming.add_type_exception(cname="%s*" % ctype, type=t)
626        naming.add_type_exception(cname=ctype, type=t)
627
628
629class Proxy(CType):
630
631    def __init__(self, ada, property=None, val_or_null=None,
632                 from_gvalue=None, default_record_field=None):
633        """:param val_or_null: is used when GIR indicates the parameter has
634           allow-none=1, and is used to test whether we should pass NULL
635           to C or a pointer to the Ada data.
636
637           :param from_gvalue: is the function used to retrieve this type from
638           a GValue, in particular when processing callbacks. The default is to
639           retrieve a C_Proxy and Cast as appropriate.
640
641           :param str default_record_field: the default value to set in record
642              type declarations for fields of that type. No default value set
643              if this is None.
644        """
645
646        if property is None:
647            CType.__init__(self, ada, "Glib.Properties.Property_Boxed")
648        else:
649            CType.__init__(self, ada, property)
650
651        self.val_or_null = val_or_null
652        self.default_record_field_value = default_record_field
653
654    def record_field_type(self, pkg=None):
655        if self.isArray and self.array_fixed_size is not None:
656            return "%s (1 .. %s)" % (
657                self.as_c_param(pkg=pkg),
658                self.array_fixed_size)
659        elif self.is_ptr or self.isArray:
660            return "access %s" % self.as_c_param(pkg=pkg)
661        else:
662            return self.as_c_param(pkg=pkg)
663
664
665class Callback(CType):
666
667    def __init__(self, ada):
668        CType.__init__(self, ada, "")
669        self.cparam = "System.Address"
670
671    def __repr__(self):
672        return "<Callback %s>" % self.ada
673
674    def convert_from_c(self):
675        # Never return such a callback to Ada (because in fact we are pointing
676        # to a function in one of the bodies of GtkAda, not the actual user
677        # callback.
678        return None
679
680    def convert_to_c(self, pkg=None):
681        return "%(var)s'Address"
682
683
684class Interface(CType):
685
686    def __init__(self, ada):
687        CType.__init__(self, ada, "Glib.Properties.Property_Interface")
688        self.cparam = ada
689        self.is_ptr = False
690
691
692class List(CType):
693
694    def __init__(self, ada):
695        CType.__init__(self, ada, "Glib.Properties.Property_Object")
696        self.__adapkg = ada[:ada.rfind(".")]
697        self.cparam = "System.Address"
698        self.is_ptr = False
699
700    def convert_from_c(self):
701        conv = "%s.Set_Object (%%(tmp)s, %%(var)s)" % self.__adapkg
702        return (   # Use %(tmp)s so forces the use of temporary var.
703            self.param, self.cparam, conv, [],
704
705            # for out parameters
706            self.cparam, conv)
707
708    @staticmethod
709    def register_ada_list(pkg, ada, ctype, single=False):
710        """Register a list of GObject instantiated in Ada"""
711        if single:
712            gtype = "GSlist"
713            name = "SList"
714        else:
715            gtype = "Glist"
716            name = "List"
717
718        listCname = "%s%s" % (ctype, name)  # Default list name
719        ada = ada or naming.type(cname=listCname).ada
720
721        t = List("%s.%s.%s" % (pkg, ada, gtype))
722        naming.add_type_exception(listCname, t)
723
724    def convert_to_c(self, pkg=None):
725        return "%s.Get_Object (%%(var)s)" % self.__adapkg
726
727    def add_with(self, pkg=None, specs=False):
728        # A list comes from an instantiation (pkg.instance.glist), so we need
729        # to skip backward two "."
730        if pkg:
731            p = self.ada.rfind(".")
732            if p != -1:
733                p = self.ada[:p].rfind(".")
734                if p != -1:
735                    pkg.add_with(self.ada[:p], specs=True)
736
737
738class AdaType(CType):
739
740    def __init__(self, adatype, pkg=None, in_spec=True, ctype="",
741                 convert="%(var)s"):
742        """The 'adatype' type is represented as 'ctype' for subprograms
743           that import C functions. The parameters of that type are converted
744           from Ada to C by using 'convert'. 'convert' must use '%s' once
745           to indicate where the name of the parameter should go
746        """
747        CType.__init__(self, adatype, "")
748        self.param = adatype
749        self.cparam = ctype or adatype
750        self.__convert = convert
751        self.cleanup = None
752        self.is_ptr = adatype.startswith("access ")
753
754        # ??? Why do we need to call this explicitly ?
755        if pkg:
756            self.add_with(pkg)
757
758    def convert_to_c(self, pkg=None):
759        return self.__convert
760
761
762class AdaTypeArray(CType):
763
764    """An array of scalar types"""
765
766    def __init__(self, adatype):
767        CType.__init__(self, adatype, "")
768        self.param = "%s_Array" % naming.case(adatype)
769        self.cparam = "System.Address"
770        self.isArray = True
771
772    def convert_to_c(self, pkg=None):
773        return "%(var)s (%(var)s'First)'Address"
774
775    def convert_from_c(self):
776        # ??? This implementation is specialized for the Gtk.Clipboard pkg,
777        # which is the only place where we use it
778        c = ("Atom_Arrays.To_Array " +
779             "(Atom_Arrays.Convert (%(var)s), Integer (N_Atoms))")
780
781        return (self.param,       # name of Ada type
782                self.cparam,      # name of C type
783                c,                # convert from C to Ada
784                [                 # list of temporary variables needed
785                ],
786                self.cparam,      # name of C type for out parameters
787                c)                # convert from previous line to Ada type
788
789
790class AdaNaming(object):
791
792    def __init__(self):
793        self.cname_to_adaname = {}  # c methods to Ada subprograms
794        self.girname_to_ctype = {}  # gir names to C types
795        self.exceptions = {}        # naming exceptions
796        self.type_exceptions = {}   # C types to CType instances
797
798    def add_type_exception(self, cname, type, override=False):
799        """Declares a new type exception, unless there already existed
800           one for that cname.
801        """
802        assert(isinstance(type, CType))
803        if override or cname not in self.type_exceptions:
804            self.type_exceptions[cname] = type
805
806    def add_cmethod(self, cname, adaname):
807        """Register the mapping from c method's name to Ada subprogram.
808           This is used to replace C function names in the documentation
809           with their Ada equivalent"""
810        self.cname_to_adaname[cname] = adaname
811
812    def add_girname(self, girname, ctype):
813        """Maps a GIR's "name" attribute to its matching C type.
814           This is used to resolve such names in the documentation and in
815           properties types.
816        """
817        self.girname_to_ctype[girname] = ctype
818
819    def ctype_from_girname(self, girname):
820        """Return the C type corresponding to a GIR name"""
821
822        if not girname:
823            return ""
824        elif girname.startswith("Gdk") or girname.startswith("Gtk"):
825            default = girname
826        else:
827            default = "Gtk%s" % girname
828
829        return self.girname_to_ctype.get(girname, default)
830
831    def adamethod_name(self, cname, warning_if_not_found=True):
832        """Return the ada name corresponding to the C method's name"""
833        try:
834            return self.cname_to_adaname[cname]
835        except KeyError:
836            if warning_if_not_found and cname.lower().startswith("gtk_"):
837                print "Name quoted in doc has no Ada binding: %s" % cname
838            self.cname_to_adaname[cname] = cname  # Display warning once only
839            return cname
840
841    def case(self, name, protect=True):
842        """Return the proper casing to use for 'name', taking keywords
843           into account. This is for packages.
844        """
845        name = self.__camel_case_to_ada(name.replace("-", "_")).title()
846        if name.endswith("_"):
847            name = name[:-1]
848
849        if protect:
850            return self.protect_keywords(name)
851        else:
852            return name
853
854    def protect_keywords(self, name):
855        return ".".join(self.exceptions.get(n, n) for n in name.split("."))
856
857    def __camel_case_to_ada(self, name):
858        """Converts a name with CamelCase to Camel_Case"""
859
860        if not name:
861            return name
862
863        result = name[0]
864        prev = result
865        prev_is_underscore = False
866        prev_is_upper = True
867
868        for r in name[1:]:
869            if prev != "_" \
870                    and prev != "." \
871                    and not prev.isupper() \
872                    and r.isupper():
873                result += "_%s" % r
874            else:
875                result += r
876
877            prev = r
878
879        return result
880
881    def __full_type_from_girname(self, girname):
882        """Return the type description from a GIR name"""
883        return self.type_exceptions.get(
884            girname,  # First try GIR name as is in the table (gint, ...)
885            self.type_exceptions.get(
886                self.ctype_from_girname(girname),  # Else the C type
887
888                # Else return the GIR name itself
889                Proxy(self.__camel_case_to_ada(girname))))
890
891    def type(self, name="", cname=None, pkg=None, isArray=False,
892             allow_access=True, allow_none=False, userecord=True,
893             useclass=True,
894             array_fixed_size=None,
895             transfer_ownership=False):
896        """Build an instance of CType for the corresponding cname.
897           A type a described in a .gir file
898
899           :param pkg: an instance of Package, to which extra
900              with clauses will be added if needed.
901           :param allow_none: if True, then an empty string maps to a
902              NULL pointer in C, rather than an empty C string. For a GObject,
903              the parameter is passed as "access" rather than
904              "not null access".
905           :param use_record: is only used for GObject types.
906           :param isArray: should be true for an array of the simple type
907              'name'.
908           :param allow_access: should be True if the parameter can be
909              represented as 'access Type', rather than an explicit type, in
910              the case of GObject descendants.
911           :param array_fixed_size: if specified, this is the size of the
912              array. The binding is different in this case, since we can't use
913              a fat pointer.
914
915        """
916
917        if cname is None:
918            cname = self.girname_to_ctype.get(name, None)
919
920        if (cname == "gchar**"
921           or name == "array_of_utf8"
922           or name == "array_of_filename"):
923            t = UTF8_List()
924        elif (cname in ("gint**", "int**")
925              or name in ("array_of_gint", "array_of_guint", "array_of_gint8",
926                          "array_of_guint8", "array_of_guint16")):
927            t = AdaTypeArray("gint")
928            isArray = True
929        elif name in ("array_of_Gdk.Atom", ):
930            t = AdaTypeArray("Gdk_Atom")
931            isArray = True
932        elif name in ("array_of_gdouble", ):
933            t = AdaTypeArray("gdouble")
934            isArray = True
935        elif cname == "void":
936            return None
937        elif name == "utf8" or cname == "gchar*" or cname == "char*":
938            t = UTF8()
939        elif name == "SignalName":
940            t = SignalName()
941        elif cname:
942            # Check whether the C type, including trailing "*", maps
943            # directly to an Ada type.
944            # t = self.type_exceptions.get(
945            #    cname,
946            #    Proxy(self.__camel_case_to_ada(cname)))
947            t = self.__full_type_from_girname(cname)
948            is_ptr = False
949
950            if t.ada[-1] == "*":
951                # No, try without the trailing "*"
952                t = self.__full_type_from_girname(cname[0:-1])
953
954                if t.ada[-1] != "*":
955                    is_ptr = True    # Yes, so we had a pointer
956                else:
957                    basename = cname[0:-1]  # Remove all "*"
958                    if basename[-1] == "*":
959                        basename = basename[0:-1]
960                    t = self.__full_type_from_girname(basename)
961
962            if not isinstance(t, GObject) \
963               and not isinstance(t, Interface):
964                t.is_ptr = is_ptr
965        else:
966            t = self.__full_type_from_girname(name)
967            t.is_ptr = cname and cname[-1] == '*'
968
969        t = t.copy()
970        t.isArray = isArray
971        t.array_fixed_size = array_fixed_size
972        t.classwide = useclass
973        t.allow_none = allow_none
974        t.userecord = userecord
975        t.transfer_ownership = transfer_ownership
976
977        # Needs to be called last, since the output might depend on all the
978        # attributes set above
979
980        t.add_with(pkg)
981
982        return t
983
984
985naming = AdaNaming()
986
987
988def max_length(iter):
989    """Return the length of the longuest element in iter"""
990    longuest = 0
991    for f in iter:
992        longuest = max(longuest, len(f))
993    return longuest
994
995
996def fill_text(text, prefix, length, firstLineLength=0):
997    """Split TEXT on several lines (with a given max length and a prefix).
998    """
999
1000    line = ""
1001    result = []
1002    maxLen = firstLineLength or length - len(prefix)
1003
1004    text = text.replace("\n\n", "\n<br>")
1005
1006    # Do we have a list item ? If yes, preserve the indentation
1007
1008    if text.lstrip().startswith("* "):
1009        line += text[:text.find("*")]
1010
1011    for w in text.split():  # for each word (this loses whitespaces)
1012        if w.startswith("<br>"):
1013            result.append(line)
1014            maxLen = length - len(prefix)
1015            line = w[4:]
1016
1017        elif len(line) + len(w) + 1 > maxLen:
1018            result.append(line)
1019            maxLen = length - len(prefix)
1020            line = w
1021
1022        elif w:
1023            line += " " + w
1024
1025    if line != "":
1026        result.append(line)
1027
1028    return ("\n" + prefix).join(result)
1029
1030
1031def cleanup_doc(doc):
1032    """Replaces C features in the doc with appropriate Ada equivalents"""
1033
1034    def replace_type(x):
1035        t = naming.type(x.group(1))
1036        t.userecord = False
1037        return t.ada
1038
1039    # get_package might have been called before we had the XML node
1040    # from the Gir file, and therefore no doc for the package. We can
1041    # now override it, unless it came from binding.xml
1042
1043    subp = re.compile("([\S_]+)\(\)")
1044    doc = subp.sub(lambda x: naming.adamethod_name(x.group(1)), doc)
1045
1046    types = re.compile("#([\w_]+)")
1047    doc = types.sub(replace_type, doc)
1048
1049    params = re.compile("@([\w_]+)")
1050    doc = params.sub(lambda x: x.group(1).title(), doc)
1051
1052    enums = re.compile("%([A-Z][\w_]+)")
1053    doc = enums.sub(lambda x: naming.adamethod_name(x.group(1)), doc)
1054
1055    doc = doc.replace("<emphasis>", "*") \
1056        .replace("</emphasis>", "*") \
1057        .replace("<literal>", "'") \
1058        .replace("</literal>", "'") \
1059        .replace("<firstterm>", "'") \
1060        .replace("</firstterm>", "'") \
1061        .replace("<![CDATA[", "") \
1062        .replace("]]>", "") \
1063        .replace("&nbsp;", " ") \
1064        .replace("<parameter>", "'") \
1065        .replace("</parameter>", "'") \
1066        .replace("<filename>", "'") \
1067        .replace("</filename>", "'") \
1068        .replace("<footnote>", "[") \
1069        .replace("</footnote>", "]") \
1070        .replace("<keycap>", "'") \
1071        .replace("</keycap>", "'") \
1072        .replace("<keycombo>", "[") \
1073        .replace("</keycombo>", "]") \
1074        .replace("<entry>", "\n\n") \
1075        .replace("</entry>", "") \
1076        .replace("<row>", "") \
1077        .replace("</row>", "") \
1078        .replace("<tbody>", "") \
1079        .replace("</tbody>", "") \
1080        .replace("</tgroup>", "") \
1081        .replace("<informaltable>", "") \
1082        .replace("</informaltable>", "") \
1083        .replace("<note>", "\nNote: ") \
1084        .replace("</note>", "")
1085
1086    doc = re.sub("<tgroup[^>]*>", "", doc)
1087    doc = re.sub("<term><parameter>(.*?)</parameter>&nbsp;:</term>",
1088                 r"\1:", doc)
1089
1090    # Lists
1091
1092    doc = re.sub("<listitem>(\n?<simpara>|\n?<para>)?", "\n\n   * ", doc)
1093
1094    doc = doc.replace("</para></listitem>", "") \
1095        .replace("</listitem>", "") \
1096        .replace("<simpara>", "") \
1097        .replace("</simpara>", "") \
1098        .replace("<para>", "\n\n") \
1099        .replace("</para>", "")
1100
1101    # Definition of terms (variablelists)
1102
1103    doc = doc.replace("<variablelist>", "") \
1104        .replace("</variablelist>", "") \
1105        .replace("<varlistentry>", "") \
1106        .replace("</varlistentry>", "") \
1107        .replace("<term>", "'") \
1108        .replace("</term>", "'")
1109
1110    doc = re.sub("<variablelist[^>]*>", "", doc)
1111    doc = re.sub("<title>(.*?)</title>", r"\n\n== \1 ==\n\n", doc)
1112    doc = re.sub("<refsect\d[^>]*>", "", doc)
1113    doc = re.sub("</refsect\d>", "", doc)
1114
1115    doc = doc.replace("<example>", "") \
1116             .replace("</example>", "") \
1117             .replace("<informalexample>", "") \
1118             .replace("</informalexample>", "") \
1119             .replace("<itemizedlist>", "").replace("</itemizedlist>", "") \
1120             .replace("<orderedlist>", "").replace("</orderedlist>", "") \
1121             .replace("&percnt;", "%") \
1122             .replace("&lt;", "<").replace("&gt;", ">") \
1123             .replace("&ast;", "*") \
1124             .replace("<programlisting>", "\n\n__PRE__<programlisting>")
1125
1126    doc = re.sub("<programlisting>(.*?)</programlisting>",
1127                 lambda m: re.sub(
1128                     "\n\n+", "\n",
1129                     indent_code(m.group(1), addnewlines=False)),
1130                 doc,
1131                 flags=re.DOTALL or re.MULTILINE)
1132
1133    doc = re.sub("\n\n\n+", "\n\n", doc)
1134
1135    return doc
1136
1137
1138def format_doc(doc, indent, separate_paragraphs=True, fill=True):
1139    """Transform the doc from a list of strings to a single string"""
1140
1141    result = ""
1142    prev = ""
1143
1144    # Make sure the doc is a list of paragraphs
1145
1146    if not isinstance(doc, list):
1147        doc = [doc]
1148
1149    # Cleanup the XML tags in each paragraph. This could result in
1150    # new paragraphs being created
1151
1152    cleaned = []
1153
1154    for d in doc:
1155        d = cleanup_doc(d)
1156        if fill:
1157            cleaned.extend(d.split("\n\n"))
1158        else:
1159            cleaned.append(d)
1160
1161    prefix = "\n" + indent + "--"
1162
1163    for d in cleaned:
1164
1165        # Separate paragraphs with an empty line, unless it is a markup
1166        # or we are at the end
1167        if separate_paragraphs:
1168            if prev != "" and not prev.lstrip().startswith("<"):
1169                result += prefix
1170
1171        if d:
1172            if d.lstrip().startswith("__PRE__"):
1173                d = d.lstrip()[7:]
1174                result += "".join(prefix + " " + p for p in d.splitlines())
1175            elif fill:
1176                result += prefix + " "
1177                result += fill_text(d, indent + "--  ", 79)
1178            else:
1179                result += "".join(prefix + " " + p for p in d.splitlines())
1180
1181            prev = d
1182
1183    if result and separate_paragraphs and result[0] == "\n":
1184        result = result[1:]
1185
1186    return result
1187
1188
1189def box(name, indent="   "):
1190    return indent + "-" * (len(name) + 6) + "\n" \
1191        + indent + "-- " + name + " --\n" \
1192        + indent + "-" * (len(name) + 6)
1193
1194
1195def indent_code(code, indent=3, addnewlines=True):
1196    """Return code properly indented and split on several lines.
1197       These are heuristics only, not perfect.
1198    """
1199    body = code.strip()
1200    if not body:
1201        return ""
1202
1203    if addnewlines:
1204        # Add newlines where needed, but preserve existing blank lines
1205        body = re.sub(";(?!\s*\n)", ";\n", body)
1206        body = re.sub("(?<!and )then(?!\s*\n)", "then\n", body)
1207        body = re.sub("(?<!or )else(?!\s*\n)", "else\n", body)
1208        body = re.sub("declare", "\ndeclare", body)
1209        body = re.sub(r"\bdo\b", "do\n", body)
1210        body = re.sub("\n\s*\n+", "\n\n", body)
1211
1212    parent_count = 0
1213    result = ""
1214
1215    for l in body.splitlines():
1216        if l.find("--") != -1:
1217            eol_comment = l[l.find("--"):].strip()
1218            l = l[:l.find("--")]
1219        else:
1220            eol_comment = ""
1221
1222        l = l.strip()
1223
1224        if l.startswith("end") \
1225           or l.startswith("elsif")  \
1226           or l.startswith("else")  \
1227           or l.startswith("begin") \
1228           or l.startswith("}"):   # for C
1229            indent -= 3
1230
1231        old_parent = parent_count
1232        parent_count = parent_count + l.count("(") - l.count(")")
1233
1234        if not l:
1235            if eol_comment:
1236                result += " " * indent
1237
1238        elif l[0] == '(':
1239            result += " " * (indent + 2)
1240            if parent_count > old_parent:
1241                indent += (parent_count - old_parent) * 3
1242        elif not old_parent:
1243            result += " " * indent
1244            if parent_count > old_parent:
1245                indent += (parent_count - old_parent) * 3
1246        else:
1247            if parent_count > old_parent:
1248                indent += (parent_count - old_parent) * 3
1249            result += " " * indent
1250
1251        if old_parent > parent_count:
1252            indent -= (old_parent - parent_count) * 3
1253
1254        result += l + eol_comment + "\n"
1255
1256        if (l.endswith("then") and not l.endswith("and then")) \
1257           or l.endswith("loop") \
1258           or(l.endswith("else") and not l.endswith("or else"))\
1259           or l.endswith("begin") \
1260           or l.endswith("{") \
1261           or l.endswith("record") \
1262           or l.endswith("is") \
1263           or l.endswith("do") \
1264           or l.endswith("declare"):
1265            indent += 3
1266
1267        # Case of generic instantiation:
1268        #     package A is
1269        #         new B ();
1270        if l.startswith("new"):
1271            indent -= 3
1272
1273    return result
1274
1275
1276# The necessary setup to use a variable in a subprogram call. The returned
1277# values map to the following Ada code:
1278#   declare
1279# $(tmpvars)    # A list of LocalVar
1280#   begin
1281#      $(precall)
1282#      Call ($(call), ...)
1283# (postcall)
1284#   end;
1285# and are used in case temporary variables are needed. If not, only 'call'
1286# will have a non-null value
1287
1288VariableCall = namedtuple('VariableCall',
1289                          ['call', 'precall', 'postcall', 'tmpvars'])
1290
1291
1292class Local_Var(object):
1293    __slots__ = ["name", "type", "default", "aliased", "constant"]
1294
1295    def __init__(self, name, type, default="", aliased=False, constant=False):
1296        self.set_type(type)
1297        self.name = name
1298        self.default = default
1299        self.aliased = aliased
1300        self.constant = constant
1301
1302    def __repr__(self):
1303        return "<Local_Var name=%s type=%s>" % (self.name, self.type)
1304
1305    def set_type(self, type):
1306        if isinstance(type, str):
1307            self.type = AdaType(type)
1308        else:
1309            self.type = type
1310
1311    def _type(self, lang, pkg):
1312        """`pkg` is the package in which we insert the variable, and is used
1313           to add necessary with statements, if any.
1314        """
1315        if lang == "ada":
1316            return self.type.as_ada_param(pkg)
1317        elif lang == "ada->c":
1318            return self.type.as_c_param(pkg)
1319        elif lang == "c->ada":
1320            return self.type.convert_from_c()[1]
1321
1322    def spec(self, pkg, length=0, lang="ada", show_default=True):
1323        """Format the declaration for the variable or parameter.
1324           'length' is the minimum length that the name should occupy (for
1325           proper alignment when there are several variables.
1326        """
1327        t = self._type(lang=lang, pkg=pkg)
1328        aliased = ""
1329        if self.aliased:
1330            aliased = "aliased "
1331
1332        if self.default and show_default:
1333            return "%-*s : %s%s%s := %s" % (
1334                length, self.name,
1335                "constant " if self.constant else "",
1336                aliased, t, self.default)
1337        else:
1338            return "%-*s : %s%s" % (length, self.name, aliased, t)
1339
1340    def as_call(self, pkg, lang="ada", value=None):
1341        """Pass self (or the value) as a parameter to an Ada subprogram call,
1342           implemented in the given language. See comments at the beginning
1343           of this package for valid values of LANG.
1344           'pkg' is the instance of Package in which the call occurs.
1345           :return: an instance of VariableCall
1346        """
1347        n = value or self.name
1348        if isinstance(self.type, CType):
1349            return self.type.as_call(
1350                name=n, pkg=pkg, lang=lang, wrapper="%s",
1351                is_temporary_variable=True)
1352        else:
1353            return VariableCall(call=n, precall='', postcall='', tmpvars=[])
1354
1355
1356class Parameter(Local_Var):
1357    __slots__ = ["name", "type", "default", "aliased", "mode", "doc",
1358                 "ada_binding", "for_function", "is_temporary_variable"]
1359
1360    def __init__(self, name, type, default="", doc="", mode="in",
1361                 for_function=False, ada_binding=True,
1362                 is_temporary_variable=False):
1363        """
1364           'mode' is the mode for the Ada subprogram, and is automatically
1365              converted when generating a subprogram as a direct C import.
1366
1367           :param for_function: whether the parameter belongs to a procedure
1368              or a function.
1369
1370           :param ada_binding: if False, the parameter will not be displayed
1371              in the profile of Ada subprograms (although, of course, it will
1372              be passed to the C subprograms)
1373
1374           :param is_temporary_variable: True if this parameter represents a
1375              local variable. In this case, we can sometimes avoid creating
1376              other such variables, a minor optimization.
1377        """
1378        assert mode in ("in", "out", "in out", "not null access",
1379                        "access"), "Incorrect mode: %s" % mode
1380
1381        super(Parameter, self).__init__(name, type, default=default)
1382        self.mode = mode
1383        self.doc = doc
1384        self.ada_binding = ada_binding
1385        self.for_function = for_function
1386        self.is_temporary_variable = is_temporary_variable
1387
1388    def _type(self, lang, pkg):
1389        mode = self.mode
1390
1391        if lang == "ada->c" and mode != "in" and self.for_function:
1392            mode = "access"
1393
1394        if mode in ("in out", "out") and hasattr(self.type, "userecord"):
1395            userec = self.type.userecord
1396            self.type.userecord = False
1397            t = super(Parameter, self)._type(lang=lang, pkg=pkg)
1398            self.type.userecord = userec
1399        else:
1400            t = super(Parameter, self)._type(lang=lang, pkg=pkg)
1401
1402        if mode != "in":
1403            return "%s %s" % (mode, t)
1404        return t
1405
1406    def as_call(self, pkg, lang="ada", value=None):
1407        """'pkg' is the package instance in which the call occurs."""
1408
1409        assert lang in ("ada", "c->ada", "ada->c")
1410
1411        if not self.ada_binding:
1412            if self.default is not None:
1413                return VariableCall(call=self.default,
1414                                    precall='', postcall='', tmpvars=[])
1415            else:
1416                return VariableCall(call="Parameter not bound in Ada",
1417                                    precall='', postcall='', tmpvars=[])
1418        else:
1419            wrapper = "%s"
1420            n = value or self.name
1421
1422            # We know that for a C function, an "in out" parameter is
1423            # implemented as an "access parameter", so we'll need to take a
1424            # 'Access. In the call to as_call() below, though, we still pass
1425            # the original mode ("in out") not "access", so that as_call()
1426            # knows whether we need to make a copy of the parameter or not.
1427
1428            if lang == "ada->c" and self.mode != "in" and self.for_function:
1429                wrapper = "%s'Access"
1430
1431            if isinstance(self.type, CType):
1432                return self.type.as_call(
1433                    name=n, pkg=pkg, lang=lang, mode=self.mode,
1434                    wrapper=wrapper,
1435                    is_temporary_variable=self.is_temporary_variable)
1436            else:
1437                return VariableCall(
1438                    call=n, precall='', postcall='', tmpvars=[])
1439
1440    def direct_c_map(self):
1441        """Whether the parameter can be passed as is to C"""
1442        return self.type.direct_c_map()
1443
1444    def value(self):
1445        if not self.ada_binding:
1446            if self.default is not None:
1447                return self.default
1448            else:
1449                return "Parameter not bound in Ada"
1450        else:
1451            return self.ada_binding
1452
1453
1454def base_name(qname):
1455    """Return the basename for a fully qualified name:
1456        Pkg.Name  => Name
1457    """
1458    if "." in qname:
1459        return qname[qname.rfind(".") + 1:]
1460    else:
1461        return qname
1462
1463
1464def package_name(qname):
1465    """Return the package part of a fully qualified name:
1466       Pkg.Child.Name  => Pkg.Child
1467       Name      => ""
1468    """
1469    if "." in qname:
1470        index = qname.rfind(".")
1471        if qname[index - 1] != '.':   # ignore ".." in ranges
1472            return qname[:index]
1473    return ""
1474
1475
1476max_profile_length = 79 - len(" is")
1477
1478
1479class Subprogram(object):
1480
1481    """An Ada subprogram that we are generating"""
1482
1483    def __init__(self, name, code="", plist=[], local_vars=[],
1484                 returns=None, doc=[], showdoc=True, convention=None,
1485                 lang="ada", allow_none=True):
1486        """Create a new subprogram.
1487           'plist' is a list of Parameter.
1488           'local_vars' is a list of Local_Var.
1489           'doc' is a string or a list of paragraphs.
1490           'code' can be the empty string, in which case no body is output.
1491           'lang' is the language for the types of parameters (see comment at
1492               the top of this file).
1493           'allow_none': when this is an anonymous subprogram (and therefore
1494               used for a callback), this indicates whether the callback can be
1495               null or not).
1496           The code will be automatically pretty-printed, and the appropriate
1497           pragma Unreferenced are also added automatically.
1498        """
1499        assert(returns is None or isinstance(returns, CType))
1500        assert(lang in ("ada", "c->ada", "ada->c"))
1501
1502        self.name = name
1503        self.plist = plist
1504        self.returns = returns
1505        self.local = local_vars
1506        self.showdoc = showdoc
1507        self.convention = convention   # "lang"
1508        self.allow_none = allow_none
1509        self._import = None
1510        self._nested = []  # nested subprograms
1511        self._deprecated = (False, "")  # True if deprecated
1512        self._manual_body = None  # Written by user explicitly
1513
1514        self.lang = lang  # Language for the types of parameters
1515
1516        if code and code[-1] != ";":
1517            self.code = code + ";"
1518        else:
1519            self.code = code
1520
1521        if isinstance(doc, list):
1522            self.doc = doc
1523        else:
1524            self.doc = [doc]
1525
1526    def import_c(self, cname):
1527        """Declares that 'self' is implemented as a pragma Import.
1528           This returns 'self' so that it can be chained:
1529              s = Subprogram(...).import_c('...')
1530        """
1531        self._import = 'pragma Import (C, %s, "%s");' % (self.name, cname)
1532        return self
1533
1534    def mark_deprecated(self, msg):
1535        """Mark the subprogram as deprecated"""
1536
1537        self._deprecated = (True, msg)
1538
1539    def add_nested(self, *args):
1540        """Add some nested subprograms"""
1541        for subp in args:
1542            self._nested.append(subp)
1543        return self
1544
1545    def set_body(self, body):
1546        """Overrides the body of the subprogram (after "is")"""
1547        self._manual_body = body
1548
1549    def profile(self, pkg, indent="   ", maxlen=max_profile_length,
1550                as_type=False, specs=False):
1551        """Compute the profile for the subprogram"""
1552
1553        returns = self.returns and self.returns.as_return(pkg=pkg)
1554
1555        if returns:
1556            prefix = "function"
1557            if self.lang == "ada->c":
1558                suffix = " return %s" % returns[1]
1559            elif self.lang == "c->ada":
1560                suffix = " return %s" % returns[1]
1561            else:
1562                suffix = " return %s" % returns[0]
1563        else:
1564            prefix = "procedure"
1565            suffix = ""
1566
1567        if (not as_type) and self.name:
1568            prefix = indent + prefix + " " + base_name(self.name)
1569        elif self.allow_none:
1570            prefix = "access %s" % prefix
1571        else:
1572            prefix = "not null access %s" % prefix
1573
1574        if self.plist:
1575            # First test: all parameters on same line
1576            plist = [p.spec(pkg=pkg, lang=self.lang) for p in self.plist]
1577            p = " (" + "; ".join(plist) + ")"
1578
1579            # If too long, split on several lines
1580            if len(p) + len(prefix) + len(suffix) > maxlen:
1581                max = max_length([p.name for p in self.plist])
1582                plist = [p.spec(pkg=pkg, length=max, lang=self.lang,
1583                                show_default=self.lang == "ada")
1584                         for p in self.plist]
1585                p = "\n   " + indent + "(" \
1586                    + (";\n    " + indent).join(plist) + ")"
1587
1588        else:
1589            p = ""
1590
1591        # Should the "return" go on a separate line ?
1592        if p and suffix and len(p.splitlines()[-1]) + len(suffix) > maxlen:
1593            return prefix + p + "\n   " + indent + suffix
1594        else:
1595            return prefix + p + suffix
1596
1597    def add_withs_for_subprogram(self, pkg, in_specs):
1598        """
1599        Add required withs to the package (either in specs or body)
1600        """
1601        if self.returns:
1602            r = self.returns.as_return(pkg=pkg)
1603            if self.lang == "ada->c":
1604                self.returns.add_with(pkg=pkg, specs=in_specs)
1605            elif self.lang == "c->ada":
1606                self.returns.add_with(pkg=pkg, specs=in_specs)
1607            else:
1608                pkg.add_with(package_name(r[0]), specs=in_specs)
1609
1610        if self.plist:
1611            for p in self.plist:
1612                p.type.add_with(pkg=pkg, specs=in_specs)
1613
1614    def formatted_doc(self, indent="   "):
1615        if self.showdoc:
1616            doc = [d for d in self.doc]
1617            if self._deprecated[0]:
1618                doc += [self._deprecated[1]]
1619            doc += [p.doc for p in self.plist]
1620        else:
1621            doc = []
1622
1623        return format_doc(doc, indent=indent, separate_paragraphs=False)
1624
1625    def spec(self, pkg, indent="   ", show_doc=True,
1626             maxlen=max_profile_length, as_type=False):
1627        """Return the spec of the subprogram"""
1628
1629        result = self.profile(
1630            pkg=pkg, indent=indent, maxlen=maxlen, as_type=as_type) + ";"
1631
1632        if self._import:
1633            result += "\n" + indent + self._import
1634
1635        if self._deprecated[0]:
1636            result += "\n" + indent + "pragma Obsolescent (%s);" % self.name
1637
1638        if self.convention:
1639            result += "\n" + indent \
1640                + "pragma Convention (%s, %s);" % (self.convention, self.name)
1641
1642        if show_doc:
1643            doc = self.formatted_doc(indent=indent)
1644        else:
1645            doc = ""
1646
1647        return result + doc
1648
1649    def _find_unreferenced(self, local_vars="", indent="   "):
1650        """List the pragma Unreferenced statements that are needed for this
1651           subprogram.
1652        """
1653        unreferenced = []
1654        for p in self.plist:
1655            if not re.search(
1656               r'\b%s\b' % p.name, self.code + local_vars, re.IGNORECASE):
1657                unreferenced.append(p.name)
1658
1659        if unreferenced:
1660            return indent + "   pragma Unreferenced (%s);\n" % (
1661                ", ".join(unreferenced))
1662        else:
1663            return ""
1664
1665    def _format_local_vars(self, pkg, indent="   "):
1666        """The list of local variable declarations"""
1667        if self.local:
1668            max = max_length([p.name for p in self.local])
1669            result = []
1670            seen = set()
1671
1672            for v in self.local:
1673                if v.name not in seen:
1674                    seen.add(v.name)
1675                    result.append(v.spec(pkg=pkg, length=max))
1676
1677            return indent + "   " + (";\n   " + indent).join(result) + ";\n"
1678        else:
1679            return ""
1680
1681    def body(self, pkg, indent="   "):
1682        if not self.code and not self._manual_body:
1683            return ""
1684
1685        result = box(base_name(self.name), indent=indent) + "\n\n"
1686        profile = self.profile(pkg=pkg, indent=indent)
1687        result += profile
1688
1689        if profile.find("\n") != -1:
1690            result += "\n" + indent + "is\n"
1691        else:
1692            result += " is\n"
1693
1694        local = self._format_local_vars(pkg=pkg, indent=indent)
1695        auto = self._find_unreferenced(local_vars=local, indent=indent)
1696
1697        for s in self._nested:
1698            auto += s.spec(pkg=pkg, indent=indent + "   ") + "\n"
1699            auto += s.body(pkg=pkg, indent=indent + "   ")
1700
1701        auto += local
1702        auto += indent + "begin\n"
1703        auto += indent_code(self.code, indent=len(indent) + 3)
1704
1705        if self._manual_body:
1706            result += indent + self._manual_body % {"auto": auto}
1707        else:
1708            result += auto
1709
1710        return result + indent + "end %s;\n" % base_name(self.name)
1711
1712    def call(self, in_pkg=None, extra_postcall="", values=dict(), lang=None):
1713        """A call to 'self'.
1714           The parameters that are passed to self are assumed to have the
1715           same name as in self's declaration. When 'self' is implemented
1716           as a pragma Import, proper conversions are done.
1717           'in_pkg' is used to fully qualify the name of the subprogram, to
1718           avoid ambiguities. This is optional. This is an instance of Package.
1719
1720           Returned value is a tuple:
1721               ("code", "variable_for_return", tmpvars=[])
1722           where "code" is the code to execute for the call, including
1723           creation of temporary variables, and "variable_for_return" is
1724           either None, or the code to get the result of the subprogram.
1725           So a call is:
1726               declare
1727                  tmp_vars;
1728               begin
1729                  code;
1730                  extra_postcall;
1731                  return variable_for_return;  --  Omitted for procedures
1732               end;
1733
1734           See comments at the beginning of this package for valid LANG values.
1735        """
1736
1737        assert(in_pkg is not None)
1738        assert(isinstance(in_pkg, Package))
1739
1740        if lang:
1741            pass
1742        elif self._import:
1743            lang = "ada->c"
1744        else:
1745            lang = "ada"
1746
1747        assert(lang in ("ada", "c->ada", "ada->c"))
1748
1749        tmpvars = []
1750        precall = ""
1751        params = []
1752        postcall = extra_postcall
1753
1754        for arg in self.plist:
1755            c = arg.as_call(
1756                pkg=in_pkg,
1757                lang=lang,   # An instance of VariableCall
1758                value=values.get(arg.name.lower(), None))
1759            params.append(c.call)
1760            tmpvars.extend(c.tmpvars)
1761            precall += c.precall
1762            postcall = c.postcall + postcall
1763
1764        if params:
1765            call = "%s (%s)" % (self.name, ", ".join(params))
1766        else:
1767            call = self.name
1768
1769        returns = self.returns and self.returns.as_return(pkg=in_pkg)
1770        if returns is not None:
1771            if lang == "ada->c":
1772                self.returns.convert_from_c_add_with(pkg=in_pkg)
1773
1774                tmpvars.extend(returns[3])
1775                if "%(tmp)s" in returns[2]:
1776                    # Result of Internal is used to create a temp. variable,
1777                    # which is then returned. This variable has the same type
1778                    # as the Ada type (not necessarily same as Internal)
1779                    call = returns[2] % {"var": call, "tmp": "Tmp_Return"}
1780
1781                    tmpvars.append(Local_Var("Tmp_Return", returns[0]))
1782                    result = ("%s%s;%s" % (precall, call, postcall),
1783                              "Tmp_Return",
1784                              tmpvars)
1785
1786                elif postcall:
1787                    tmpvars.append(Local_Var("Tmp_Return", returns[1]))
1788                    call = "Tmp_Return := %s" % call
1789                    result = ("%s%s;%s" % (precall, call, postcall),
1790                              returns[2] % {"var": "Tmp_Return"},
1791                              tmpvars)
1792
1793                else:
1794                    # No need for a temporary variable
1795                    result = (precall, returns[2] % {"var": call}, tmpvars)
1796
1797            else:  # "ada" or "c->ada"
1798                if postcall:
1799                    # We need to use a temporary variable, since there are
1800                    # cleanups to perform. This will not work if the function
1801                    # returns an unconstrained array though.
1802                    tmpvars.append(Local_Var("Tmp_Return", returns[0]))
1803                    call = "Tmp_Return := %s" % call
1804                    result = ("%s%s;%s" % (precall, call, postcall),
1805                              "Tmp_Return",
1806                              tmpvars)
1807                else:
1808                    # No need for a temporary variable
1809                    result = (precall, call, tmpvars)
1810
1811        else:
1812            # A procedure
1813            result = ("%s%s;%s" % (precall, call, postcall), None, tmpvars)
1814
1815        return result
1816
1817    def call_to_string(self, call, pkg=None, lang="ada"):
1818        """CALL is the result of call() above.
1819           This function returns a string that contains the code for the
1820           subprogram.
1821        """
1822        result = call[0]
1823        if call[1]:
1824            if lang == "c->ada":
1825                # The return value (Ada) needs to be converted back to C (this
1826                # is the returned value from a callback, for instance)
1827                result += "return %s" % (
1828                    self.returns.convert_to_c(pkg=pkg) % {"var": call[1]}, )
1829            else:
1830                result += "return %s" % call[1]
1831        return result
1832
1833
1834class Code(object):
1835    """
1836    Some text to insert in a package.  This can be either some code, or the
1837    comments for the code. In the latter case, the comment will be
1838    automatically formatted (and C names substituted as appropriate).
1839    """
1840
1841    def __init__(self, content, iscomment=False, fill=True):
1842        """:param:`fill` whether to reflow the text if this is a comment.
1843           :param:`add_newline` whether the block should have a leading newline
1844        """
1845        self.content = content
1846        self.iscomment = iscomment
1847        self.fill = fill
1848        self.add_newline = True
1849
1850    def format(self, indent=""):
1851        """Return the code that should be written into a package"""
1852        if self.iscomment:
1853            return format_doc(self.content, indent=indent, fill=self.fill)
1854        else:
1855            return indent_code(
1856                self.content, indent=len(indent), addnewlines=False)
1857
1858
1859class Section(object):
1860    """A group of types and subprograms in an Ada package.
1861       There is a single section with a given name in the package
1862    """
1863
1864    group_getters_and_setters = False
1865    # If true, a getter will be displayed with its corresponding setter.
1866    # Only one doc will be displayed for the two, and no separation line
1867    # will be output.
1868
1869    sort_alphabetically = False
1870    # If true, subprograms are all sorted alphabetically, otherwise the
1871    # order is alphabetical for getters, but setters appear just after the
1872    # getter.
1873
1874    def __init__(self, pkg, name):
1875        self.pkg = pkg  # The instance of Package in which the section is
1876        self.name = name
1877        self.__comment = ""
1878        self.__objects = []  # List of objects. These are tuples:
1879        #    (Code or Subprogram or Package instance,
1880        #     in_spec)
1881
1882        # Whether we should sort the objects. If yes, code always comes before
1883        # subprograms. Otherwise, they are output in the order they were added
1884        self.sort_objects = (
1885            not Section.sort_alphabetically
1886            or Section.group_getters_and_setters)
1887
1888    def add_comment(self, comment, fill=True):
1889        """If 'fill' is true, the comment is automatically split on several
1890           lines if needed. Otherwise, the comment is assumed to be already
1891           formatted properly, minus the leading --
1892        """
1893        if comment == "":
1894            self.__comment += "   --\n"
1895        else:
1896            self.__comment += "".join(
1897                format_doc(comment, indent="   ", fill=fill)) + \
1898                "\n"
1899
1900    def add(self, obj, in_spec=True, add_newline=True):
1901        """Add one or more objects to the section (subprogram, code,...).
1902           :param:`add_newline` indicates whether the object should be
1903           followed by a blank line. There is never a blank line between some
1904           code and the following comment.
1905        """
1906
1907        iscode = False
1908
1909        if isinstance(obj, str) or isinstance(obj, unicode):
1910            obj = Code(obj)
1911            iscode = True
1912        elif isinstance(obj, Package):
1913            obj.isnested = True
1914
1915        obj.add_newline = add_newline
1916
1917        if iscode:
1918            #  Take care of duplicated entries. May happen in case of
1919            #  subpackages in GIR files
1920            for o, s in self.__objects:
1921                if s == in_spec and isinstance(o, Code):
1922                    if o.content == obj.content:
1923                        return False
1924        self.__objects.append((obj, in_spec))
1925
1926        return True
1927
1928    def _group_objects(self):
1929        """Returns a list of subprograms for the specs. In each nested list,
1930           the subprograms are grouped and a single documentation is output for
1931           the whole group. At the same time, this preserves the order of
1932           groups, so they appear in the order in which the first subprogram
1933           in the group appeared.
1934        """
1935
1936        if self.sort_objects:
1937            code = []
1938            subprograms = []
1939            tmp = dict()  # group_name => [subprograms]
1940
1941            gtk_new_index = 0
1942
1943            for obj, in_spec in self.__objects:
1944                if not in_spec:
1945                    continue
1946
1947                if isinstance(obj, Code) or isinstance(obj, unicode):
1948                    code.append([obj])
1949
1950                elif isinstance(obj, Subprogram) or isinstance(obj, Package):
1951                    b = base_name(obj.name)
1952                    name = b.replace("Get_", "") \
1953                        .replace("Query_", "") \
1954                        .replace("Gtk_New", "") \
1955                        .replace("Gdk_New", "") \
1956                        .replace("Initialize", "") \
1957                        .replace("Set_From_", "") \
1958                        .replace("Set_", "")
1959
1960                    if b in ("Gtk_New", "Gdk_New", "G_New"):
1961                        # Always create a new group for Gtk_New, since they all
1962                        # have different parameters. But we still want to group
1963                        # Gtk_New and Initialize.
1964                        t = tmp["Gtk_New%d" % gtk_new_index] = [obj]
1965                        subprograms.append(t)
1966                    elif b == "Initialize":
1967                        tmp["Gtk_New%d" % gtk_new_index].append(obj)
1968                        gtk_new_index += 1
1969                    elif name in tmp:
1970                        tmp[name].append(obj)  # Also modified in result
1971                    else:
1972                        tmp[name] = [obj]
1973                        subprograms.append(tmp[name])
1974
1975                else:
1976                    print("Unexpected contents in package %s\n" %
1977                          (type(obj), ))
1978
1979            return code + subprograms
1980
1981        else:
1982            return [[obj]
1983                    for obj, in_spec in self.__objects
1984                    if in_spec]
1985
1986    def spec(self, pkg, indent):
1987        """Return the spec of the section"""
1988
1989        result = ""
1990        add_newline = False
1991
1992        for group in self._group_objects():
1993            for obj in group:
1994                # If the previous object requested a trailing newline, and the
1995                # current object is not a comment, then add the newline now.
1996                if (add_newline
1997                    and (not isinstance(obj, Code)
1998                         or not obj.iscomment)):
1999
2000                    result += "\n"
2001
2002                if isinstance(obj, Code):
2003                    result += obj.format(indent=indent).strip("\n") + "\n"
2004                    add_newline = obj.add_newline
2005
2006                elif isinstance(obj, Subprogram):
2007                    show_doc = ((not Section.group_getters_and_setters
2008                                 and not obj.name.startswith("Gtk_New"))
2009                                or obj == group[-1])
2010                    result += obj.spec(pkg=pkg,
2011                                       show_doc=show_doc,
2012                                       indent=indent).strip("\n") + "\n"
2013                    add_newline = (hasattr(obj, "add_newline")
2014                                   and obj.add_newline
2015                                   and show_doc)
2016
2017                elif isinstance(obj, Package):
2018                    result += obj.spec().strip("\n") + "\n"
2019                    add_newline = (hasattr(obj, "add_newline")
2020                                   and obj.add_newline)
2021
2022                elif isinstance(obj, unicode):
2023                    print("Not adding unicode to package: %s\n" % (
2024                        obj.encode('UTF-8'), ))
2025
2026        if add_newline:
2027            result += "\n"
2028
2029        if result:
2030            if self.__comment:
2031                result = self.__comment + "\n" + result
2032            elif self.name:
2033                result = "\n" + result
2034            if self.name:
2035                result = box(self.name) + "\n" + result
2036
2037        return result
2038
2039    def body(self, pkg, indent):
2040        result = []
2041
2042        for obj, in_spec in self.__objects:
2043            if in_spec or not isinstance(obj, Code):
2044                continue
2045            result.append(obj.format(indent=indent))  # ignores obj.add_newline
2046
2047        body_subprograms = [(obj, in_spec) for obj, in_spec in self.__objects
2048                            if not isinstance(obj, Code)]
2049        body_subprograms.sort(key=lambda x: base_name(x[0].name))
2050
2051        # First output for the subprograms only defined in the body
2052
2053        for obj, in_spec in body_subprograms:
2054            if not in_spec:
2055                if isinstance(obj, Subprogram):
2056                    result.append(obj.spec(pkg=pkg, indent=indent))
2057                else:
2058                    result.append(obj.spec())
2059                result.append("")
2060
2061        # Then output all the bodiesx
2062
2063        for obj, in_spec in body_subprograms:
2064            if isinstance(obj, Subprogram):
2065                b = obj.body(pkg=pkg, indent=indent)
2066            else:
2067                b = obj.body() + "\n"
2068            if b:
2069                result.append(b)
2070
2071        return "\n".join(result)
2072
2073
2074class Package(object):
2075    copyright_header = ""
2076    # Can be overridden by applications to change the copyright header
2077
2078    def __init__(self, name, doc=[], isnested=False):
2079        """'doc' is a list of strings, where each string is a paragraph"""
2080        self.name = name
2081        self.doc = doc
2082
2083        self.sections = []       # [Section]
2084        self.spec_withs = dict()  # "pkg" -> use:Boolean
2085        self.body_withs = dict()  # "pkg" -> use:Boolean
2086        self.private = []        # Private section
2087        self.language_version = ""  # a pragma to be put just after the headers
2088        self.formal_params = ""  # generic formal parameters
2089        self.isnested = isnested
2090
2091    def __repr__(self):
2092        return "<Package %s>" % self.name
2093
2094    def section(self, name):
2095        """Return an existing section (or create a new one) with the given
2096           name.
2097        """
2098        for s in self.sections:
2099            if s.name == name:
2100                return s
2101
2102        s = Section(self, name)
2103        self.sections.append(s)
2104        return s
2105
2106    def add_with(self, pkg, specs=True, do_use=True, might_be_unused=False):
2107        """Add a with+use clause for pkg, where pkg can also be a list.
2108           Automatic casing is performed. If specs is True, the withs are
2109           added to the specs of the package, otherwise to the body.
2110
2111           :param:`might_be_unused` True if the package might not be used and
2112              requires a pragma Warnings Off.
2113        """
2114        if pkg in ("", "System"):
2115            return
2116
2117        if type(pkg) == str:
2118            pkg = [pkg]
2119        for p in pkg:
2120            if p.lower() == self.name.lower():
2121                continue   # No dependence on self
2122
2123            p_info = (
2124                do_use or self.spec_withs.get(p, False),   # do_use
2125                might_be_unused)
2126
2127            if specs:
2128                self.spec_withs[p] = p_info
2129                self.body_withs.pop(p, None)  # Remove same with in body
2130            elif p not in self.spec_withs:
2131                self.body_withs[p] = p_info
2132
2133    def add_private(self, code, at_end=False):
2134        if at_end:
2135            self.private.append(code)
2136        else:
2137            self.private.insert(0, code)
2138
2139    def _output_withs(self, withs):
2140        if withs:
2141            result = []
2142            m = max_length(withs)
2143            had_warnings_off = False
2144
2145            # sort so that all packages for which 'might_be_unused' is True
2146            # are last in the list
2147
2148            for w in sorted(withs.keys(),
2149                            key=lambda w: 'zz%s' % w if withs[w][1] else w):
2150                do_use, might_be_unused = withs[w]
2151
2152                if might_be_unused and not had_warnings_off:
2153                    result.append("pragma Warnings(Off);  --  might be unused")
2154                    had_warnings_off = True
2155
2156                if do_use:
2157                    result.append(
2158                        "with %-*s use %s;" % (m + 1, w + ";", w))
2159                else:
2160                    result.append("with %s;" % w)
2161
2162            if had_warnings_off:
2163                result.append("pragma Warnings(On);")
2164
2165            return "\n".join(result) + "\n"
2166        return ""
2167
2168    def section_order(self, name):
2169        """Return a numerical order for sections"""
2170        order = {"": 0,
2171                 "Callbacks": 1,
2172                 "Enumeration Properties": 2,
2173
2174                 # Primitive operations first
2175                 "Constructors": 3,
2176                 "Methods": 4,
2177                 "GtkAda additions": 5,
2178                 "Inherited subprograms (from interfaces)": 6,
2179
2180                 # Then non-primitive (so that we can freeze the type, for
2181                 # instance by instantiating lists)
2182                 "Functions": 8,
2183                 "Lists": 9,
2184
2185                 # General data independent of the type
2186                 "Properties": 10,
2187                 "Signals": 11,
2188
2189                 # Instantiating new generic packages freezes the types, so
2190                 # should be last
2191                 "Interfaces": 12,
2192                 }
2193        return order.get(name, 1000)
2194
2195    def spec(self):
2196        """Returns the spec of the package, in the file `out`"""
2197
2198        result = []
2199
2200        if not self.isnested:
2201            indent = ""
2202            if Package.copyright_header:
2203                result.append(Package.copyright_header)
2204
2205            if self.language_version:
2206                result.append(self.language_version)
2207
2208            if self.doc:
2209                result.append(format_doc(self.doc, indent=""))
2210
2211            result.append("pragma Ada_2005;\n")
2212            result.append('pragma Warnings (Off, "*is already use-visible*");')
2213            result.append(self._output_withs(self.spec_withs))
2214
2215        else:
2216            indent = "   "
2217
2218        if self.formal_params:
2219            result.append(indent + "generic")
2220            result.append(indent + "   %s" % self.formal_params)
2221        result.append(indent + "package %s is\n" % self.name)
2222
2223        self.sections.sort(lambda x, y: cmp(self.section_order(x.name),
2224                                            self.section_order(y.name)))
2225
2226        for s in self.sections:
2227            sec = s.spec(pkg=self, indent=indent + "   ")
2228            if sec:
2229                result.append(sec.strip("\n") + "\n")
2230
2231        if self.private:
2232            result.append(indent + "private")
2233            result.extend(self.private)
2234
2235        result.append(indent + "end %s;" % self.name)
2236        return "\n".join(result)
2237
2238    def body(self):
2239        """Returns the body of the package"""
2240
2241        result = []
2242        body = ""
2243
2244        if self.isnested:
2245            indent = "   "
2246        else:
2247            indent = ""
2248
2249        for s in self.sections:
2250            b = s.body(pkg=self, indent=indent + "   ")
2251            if b:
2252                body += "\n" + b
2253
2254        if not body:
2255            return ""
2256
2257        if not self.isnested:
2258            if Package.copyright_header:
2259                result.append(Package.copyright_header)
2260
2261            if self.language_version:
2262                result.append(self.language_version)
2263
2264            result.append("pragma Style_Checks (Off);")
2265            result.append('pragma Warnings (Off, "*is already use-visible*");')
2266            result.append(self._output_withs(self.body_withs))
2267
2268        result.append(indent + "package body %s is" % self.name)
2269        result.append(body)
2270        result.append(indent + "end %s;" % self.name)
2271        return "\n".join(result)
2272