Type.py revision 6657:ef5fae93a3b2
14304SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
24304SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company
34304SN/A# All rights reserved.
410036SN/A#
58835SN/A# Redistribution and use in source and binary forms, with or without
610036SN/A# modification, are permitted provided that the following conditions are
77935SN/A# met: redistributions of source code must retain the above copyright
87935SN/A# notice, this list of conditions and the following disclaimer;
97935SN/A# redistributions in binary form must reproduce the above copyright
104304SN/A# notice, this list of conditions and the following disclaimer in the
114304SN/A# documentation and/or other materials provided with the distribution;
124304SN/A# neither the name of the copyright holders nor the names of its
1310315SN/A# contributors may be used to endorse or promote products derived from
148835SN/A# this software without specific prior written permission.
159885SN/A#
169885SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1710036SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
188835SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
198835SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2010315SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
218835SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2210315SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239481SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249481SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258625SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2610900Snilay@cs.wisc.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278721SN/A
288835SN/Afrom m5.util import code_formatter, orderdict
298835SN/A
307935SN/Afrom slicc.util import PairContainer
317935SN/Afrom slicc.symbols.Symbol import Symbol
327935SN/A
337935SN/Aclass DataMember(PairContainer):
347935SN/A    def __init__(self, ident, type, pairs, init_code):
357935SN/A        super(DataMember, self).__init__(pairs)
367935SN/A        self.ident = ident
378983SN/A        self.type = type
384304SN/A        self.init_code = init_code
399885SN/A
409885SN/Aclass Enumeration(PairContainer):
419885SN/A    def __init__(self, ident, pairs):
4210315SN/A        super(Enumeration, self).__init__(pairs)
4310036SN/A        self.ident = ident
4410315SN/A
459885SN/Aclass Method(object):
469885SN/A    def __init__(self, return_type, param_types):
474304SN/A        self.return_type = return_type
484304SN/A        self.param_types = param_types
499481SN/A
5010315SN/Aclass Type(Symbol):
515876SN/A    def __init__(self, table, ident, location, pairs, machine=None):
529885SN/A        super(Type, self).__init__(table, ident, location, pairs)
534304SN/A        self.c_ident = ident
545876SN/A        if machine:
558835SN/A            if self.isExternal or self.isPrimitive:
565876SN/A                if "external_name" in self:
575000SN/A                    self.c_ident = self["external_name"]
5810036SN/A            else:
594304SN/A                # Append with machine name
604304SN/A                self.c_ident = "%s_%s" % (machine, ident)
618835SN/A
629481SN/A        self.pairs.setdefault("desc", "No description avaliable")
635000SN/A
644304SN/A        # check for interface that this Type implements
654304SN/A        if "interface" in self:
664304SN/A            interface = self["interface"]
674304SN/A            if interface in ("Message", "NetworkMessage"):
685575SN/A                self["message"] = "yes"
698835SN/A            if interface == "NetworkMessage":
704304SN/A                self["networkmessage"] = "yes"
719885SN/A
7210315SN/A        # FIXME - all of the following id comparisons are fragile hacks
739481SN/A        if self.ident in ("CacheMemory", "NewCacheMemory",
744304SN/A                          "TLCCacheMemory", "DNUCACacheMemory",
754971SN/A                          "DNUCABankCacheMemory", "L2BankCacheMemory",
764304SN/A                          "CompressedCacheMemory", "PrefetchCacheMemory"):
774304SN/A            self["cache"] = "yes"
784304SN/A
794304SN/A        if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"):
804304SN/A            self["tbe"] = "yes"
8111066Snilay@cs.wisc.edu
829885SN/A        if self.ident == "NewTBETable":
838983SN/A            self["newtbe"] = "yes"
844304SN/A
859885SN/A        if self.ident == "TimerTable":
8610900Snilay@cs.wisc.edu            self["timer"] = "yes"
8710036SN/A
886123SN/A        if self.ident == "DirectoryMemory":
899481SN/A            self["dir"] = "yes"
9010900Snilay@cs.wisc.edu
914304SN/A        if self.ident == "PersistentTable":
929481SN/A            self["persistent"] = "yes"
935876SN/A
948835SN/A        if self.ident == "Prefetcher":
959481SN/A            self["prefetcher"] = "yes"
9610036SN/A
974304SN/A        if self.ident == "DNUCA_Movement":
988835SN/A            self["mover"] = "yes"
999885SN/A
1009481SN/A        self.isMachineType = (ident == "MachineType")
1014304SN/A
1024304SN/A        self.data_members = orderdict()
1038983SN/A
1044304SN/A        # Methods
1059885SN/A        self.methods = {}
1069885SN/A
1079885SN/A        # Enums
1089885SN/A        self.enums = orderdict()
1099885SN/A
11010036SN/A    @property
1119885SN/A    def isPrimitive(self):
11210036SN/A        return "primitive" in self
1139885SN/A    @property
1149885SN/A    def isNetworkMessage(self):
1155000SN/A        return "networkmessage" in self
1166024SN/A    @property
11710036SN/A    def isMessage(self):
1185000SN/A        return "message" in self
1195000SN/A    @property
1204304SN/A    def isBuffer(self):
12111066Snilay@cs.wisc.edu        return "buffer" in self
1229885SN/A    @property
1238983SN/A    def isInPort(self):
1244304SN/A        return "inport" in self
1259885SN/A    @property
12610900Snilay@cs.wisc.edu    def isOutPort(self):
12710036SN/A        return "outport" in self
1286123SN/A    @property
1299481SN/A    def isEnumeration(self):
13010900Snilay@cs.wisc.edu        return "enumeration" in self
1314304SN/A    @property
1329481SN/A    def isExternal(self):
1335876SN/A        return "external" in self
1348835SN/A    @property
1359481SN/A    def isGlobal(self):
13610036SN/A        return "global" in self
1374304SN/A    @property
1388835SN/A    def isInterface(self):
1399885SN/A        return "interface" in self
1409481SN/A
1414304SN/A    # Return false on error
1424304SN/A    def dataMemberAdd(self, ident, type, pairs, init_code):
1438983SN/A        if ident in self.data_members:
1444304SN/A            return False
1459885SN/A
1469885SN/A        member = DataMember(ident, type, pairs, init_code)
1479885SN/A        self.data_members[ident] = member
1489885SN/A
1499885SN/A        return True
15010036SN/A
1519885SN/A    def dataMemberType(self, ident):
15210036SN/A        return self.data_members[ident].type
1539885SN/A
1549885SN/A    def methodId(self, name, param_type_vec):
1558835SN/A        return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
1568835SN/A
15710036SN/A    def methodAdd(self, name, return_type, param_type_vec):
1588835SN/A        ident = self.methodId(name, param_type_vec)
1599481SN/A        if ident in self.methods:
1609481SN/A            return False
16110036SN/A
1629481SN/A        self.methods[ident] = Method(return_type, param_type_vec)
1635000SN/A        return True
1646024SN/A
16510036SN/A    def enumAdd(self, ident, pairs):
1665000SN/A        if ident in self.enums:
1675000SN/A            return False
1684304SN/A
16911066Snilay@cs.wisc.edu        self.enums[ident] = Enumeration(ident, pairs)
1709885SN/A
1718983SN/A        # Add default
1729481SN/A        if "default" not in self:
1739885SN/A            self["default"] = "%s_NUM" % self.c_ident
17410900Snilay@cs.wisc.edu
17510036SN/A        return True
1766123SN/A
1779481SN/A    def writeCodeFiles(self, path):
17810900Snilay@cs.wisc.edu        if self.isExternal:
1794304SN/A            # Do nothing
1809481SN/A            pass
1815876SN/A        elif self.isEnumeration:
1828835SN/A            self.printEnumHH(path)
1839481SN/A            self.printEnumCC(path)
18410036SN/A        else:
1854304SN/A            # User defined structs and messages
1868835SN/A            self.printTypeHH(path)
1879885SN/A            self.printTypeCC(path)
1889481SN/A
1894304SN/A    def printTypeHH(self, path):
1908983SN/A        code = code_formatter()
1918983SN/A        code('''
1924304SN/A/** \\file ${{self.c_ident}}.hh
1939885SN/A *
1949885SN/A *
1959885SN/A * Auto generated C++ code started by $__file__:$__line__
1969885SN/A */
1979885SN/A
19810036SN/A#ifndef ${{self.c_ident}}_H
1999885SN/A#define ${{self.c_ident}}_H
20010036SN/A
2019885SN/A#include "mem/ruby/common/Global.hh"
2029885SN/A#include "mem/gems_common/Allocator.hh"
2034304SN/A''')
20410451SN/A
2059885SN/A        for dm in self.data_members.values():
20610036SN/A            if not dm.type.isPrimitive:
20710900Snilay@cs.wisc.edu                code('#include "mem/protocol/$0.hh"', dm.type.c_ident)
20810900Snilay@cs.wisc.edu
20910900Snilay@cs.wisc.edu        parent = ""
21010451SN/A        if "interface" in self:
21110900Snilay@cs.wisc.edu            code('#include "mem/protocol/$0.hh"', self["interface"])
2129885SN/A            parent = " :  public %s" % self["interface"]
2137524SN/A
2149481SN/A        code('''
2158983SN/A$klass ${{self.c_ident}}$parent {
2168983SN/A  public:
2174304SN/A    ${{self.c_ident}}()
2184971SN/A''', klass="class")
2194971SN/A
22010036SN/A        # Call superclass constructor
2214971SN/A        if "interface" in self:
2224304SN/A            code('        : ${{self["interface"]}}()')
2234304SN/A
2244304SN/A        code.indent()
22510900Snilay@cs.wisc.edu        code("{")
22610900Snilay@cs.wisc.edu        if not self.isGlobal:
2274304SN/A            code.indent()
2284304SN/A            for dm in self.data_members.values():
2295520SN/A                ident = dm.ident
2304304SN/A                if "default" in dm:
23110036SN/A                    # look for default value
23210315SN/A                    code('m_$ident = ${{dm["default"]}}; // default for this field')
2334304SN/A                elif "default" in dm.type:
2344304SN/A                    # Look for the type default
23510900Snilay@cs.wisc.edu                    tid = dm.type.c_ident
2365285SN/A                    code('m_$ident = ${{dm.type["default"]}}; // default value of $tid')
2374304SN/A                else:
2384304SN/A                    code('// m_$ident has no default')
2394304SN/A            code.dedent()
2405509SN/A        code('}')
2414304SN/A
2424304SN/A        # ******** Default destructor ********
24310451SN/A        code('~${{self.c_ident}}() { };')
2444304SN/A
2459885SN/A        # ******** Full init constructor ********
2469885SN/A        if not self.isGlobal:
2479885SN/A            params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \
24810315SN/A                       for dm in self.data_members.itervalues() ]
24910036SN/A
25010315SN/A            if self.isMessage:
2519885SN/A                params.append('const unsigned local_proc_id')
2529885SN/A
25310315SN/A            params = ', '.join(params)
25410315SN/A            code('${{self.c_ident}}($params)')
25510315SN/A
25610315SN/A            # Call superclass constructor
25710315SN/A            if "interface" in self:
25810315SN/A                code('    : ${{self["interface"]}}()')
25910315SN/A
26010315SN/A            code('{')
2614304SN/A            code.indent()
26210451SN/A            for dm in self.data_members.values():
2639885SN/A                code('m_${{dm.ident}} = local_${{dm.ident}};')
26410036SN/A                if "nextLineCallHack" in dm:
26510900Snilay@cs.wisc.edu                    code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};')
26610900Snilay@cs.wisc.edu
26710900Snilay@cs.wisc.edu            if self.isMessage:
26810451SN/A                code('proc_id = local_proc_id;')
26910900Snilay@cs.wisc.edu
2709885SN/A            code.dedent()
2717524SN/A            code('}')
27210900Snilay@cs.wisc.edu
2739150SN/A        # create a static factory method
2748983SN/A        if "interface" in self:
2754304SN/A            code('''
2764304SN/Astatic ${{self["interface"]}}* create() {
2778983SN/A    return new ${{self.c_ident}}();
2789481SN/A}
2799885SN/A''')
2809885SN/A
28110036SN/A        # ******** Message member functions ********
2828983SN/A        # FIXME: those should be moved into slicc file, slicc should
2835520SN/A        # support more of the c++ class inheritance
2845509SN/A
2855509SN/A        if self.isMessage:
2864304SN/A            code('''
2878983SN/AMessage* clone() const { checkAllocator(); return s_allocator_ptr->allocate(*this); }
2884304SN/Avoid destroy() { checkAllocator(); s_allocator_ptr->deallocate(this); }
2899885SN/Astatic Allocator<${{self.c_ident}}>* s_allocator_ptr;
2909885SN/Astatic void checkAllocator() { if (s_allocator_ptr == NULL) { s_allocator_ptr = new Allocator<${{self.c_ident}}>; }}
29110036SN/A''')
2929885SN/A
2939885SN/A        if not self.isGlobal:
294            # const Get methods for each field
295            code('// Const accessors methods for each field')
296            for dm in self.data_members.values():
297                code('''
298/** \\brief Const accessor method for ${{dm.ident}} field.
299 *  \\return ${{dm.ident}} field
300 */
301const ${{dm.type.c_ident}}& get${{dm.ident}}() const { return m_${{dm.ident}}; }
302''')
303
304            # Non-const Get methods for each field
305            code('// Non const Accessors methods for each field')
306            for dm in self.data_members.values():
307                code('''
308/** \\brief Non-const accessor method for ${{dm.ident}} field.
309 *  \\return ${{dm.ident}} field
310 */
311${{dm.type.c_ident}}& get${{dm.ident}}() { return m_${{dm.ident}}; }
312''')
313
314            #Set methods for each field
315            code('// Mutator methods for each field')
316            for dm in self.data_members.values():
317                code('''
318/** \\brief Mutator method for ${{dm.ident}} field */
319void set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) { m_${{dm.ident}} = local_${{dm.ident}}; }
320''')
321
322        code('void print(ostream& out) const;')
323        code.dedent()
324        code('  //private:')
325        code.indent()
326
327        # Data members for each field
328        for dm in self.data_members.values():
329            if "abstract" not in dm:
330                const = ""
331                init = ""
332
333                # global structure
334                if self.isGlobal:
335                    const = "static const "
336
337                # init value
338                if dm.init_code:
339                    # only global structure can have init value here
340                    assert self.isGlobal
341                    init = " = %s" % (dm.init_code)
342
343                desc = ""
344                if "desc" in dm:
345                    desc = '/**< %s */' % dm["desc"]
346
347                code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init; $desc')
348
349        if self.isMessage:
350            code('unsigned proc_id;')
351
352        code.dedent()
353        code('};')
354
355        code('''
356// Output operator declaration
357ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj);
358
359// Output operator definition
360extern inline
361ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj)
362{
363    obj.print(out);
364    out << flush;
365    return out;
366}
367
368#endif // ${{self.c_ident}}_H
369''')
370
371        code.write(path, "%s.hh" % self.c_ident)
372
373    def printTypeCC(self, path):
374        code = code_formatter()
375
376        code('''
377/** \\file ${{self.c_ident}}.cc
378 *
379 * Auto generated C++ code started by $__file__:$__line__
380 */
381
382#include "mem/protocol/${{self.c_ident}}.hh"
383''')
384
385        if self.isMessage:
386            code('Allocator<${{self.c_ident}}>* ${{self.c_ident}}::s_allocator_ptr = NULL;')
387        code('''
388/** \\brief Print the state of this object */
389void ${{self.c_ident}}::print(ostream& out) const
390{
391    out << "[${{self.c_ident}}: ";
392''')
393
394        # For each field
395        code.indent()
396        for dm in self.data_members.values():
397            code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
398
399        if self.isMessage:
400            code('out << "Time = " << getTime() << " ";')
401        code.dedent()
402
403        # Trailer
404        code('''
405    out << "]";
406}''')
407
408        code.write(path, "%s.cc" % self.c_ident)
409
410    def printEnumHH(self, path):
411        code = code_formatter()
412        code('''
413/** \\file ${{self.c_ident}}.hh
414 *
415 * Auto generated C++ code started by $__file__:$__line__
416 */
417#ifndef ${{self.c_ident}}_H
418#define ${{self.c_ident}}_H
419
420#include "mem/ruby/common/Global.hh"
421
422/** \\enum ${{self.c_ident}}
423 *  \\brief ${{self.desc}}
424 */
425enum ${{self.c_ident}} {
426    ${{self.c_ident}}_FIRST,
427''')
428
429        code.indent()
430        # For each field
431        for i,(ident,enum) in enumerate(self.enums.iteritems()):
432            desc = enum.get("desc", "No description avaliable")
433            init = ' = %s_FIRST' % self.c_ident if i == 0 else ''
434
435            code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
436        code.dedent()
437        code('''
438    ${{self.c_ident}}_NUM
439};
440${{self.c_ident}} string_to_${{self.c_ident}}(const string& str);
441string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
442${{self.c_ident}} &operator++(${{self.c_ident}} &e);
443''')
444
445        # MachineType hack used to set the base component id for each Machine
446        if self.isMachineType:
447            code('''
448int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
449MachineType ${{self.c_ident}}_from_base_level(int);
450int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
451int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
452''')
453
454            for enum in self.enums.itervalues():
455                code('#define MACHINETYPE_${{enum.ident}} 1')
456
457        # Trailer
458        code('''
459ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj);
460
461#endif // ${{self.c_ident}}_H
462''')
463
464        code.write(path, "%s.hh" % self.c_ident)
465
466    def printEnumCC(self, path):
467        code = code_formatter()
468        code('''
469/** \\file ${{self.c_ident}}.hh
470 *
471 * Auto generated C++ code started by $__file__:$__line__
472 */
473
474#include "mem/protocol/${{self.c_ident}}.hh"
475
476''')
477
478        if self.isMachineType:
479            code('#include "mem/protocol/ControllerFactory.hh"')
480            for enum in self.enums.itervalues():
481                code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
482
483        code('''
484ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj)
485{
486    out << ${{self.c_ident}}_to_string(obj);
487    out << flush;
488    return out;
489}
490
491string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
492{
493    switch(obj) {
494''')
495
496        # For each field
497        code.indent()
498        for enum in self.enums.itervalues():
499            code('  case ${{self.c_ident}}_${{enum.ident}}:')
500            code('    return "${{enum.ident}}";')
501        code.dedent()
502
503        # Trailer
504        code('''
505      default:
506        ERROR_MSG("Invalid range for type ${{self.c_ident}}");
507        return "";
508    }
509}
510
511${{self.c_ident}} string_to_${{self.c_ident}}(const string& str)
512{
513''')
514
515        # For each field
516        code.indent()
517        code("if (false) {")
518        start = "} else "
519        for enum in self.enums.itervalues():
520            code('${start}if (str == "${{enum.ident}}") {')
521            code('    return ${{self.c_ident}}_${{enum.ident}};')
522        code.dedent()
523
524        code('''
525    } else {
526        WARN_EXPR(str);
527        ERROR_MSG("Invalid string conversion for type ${{self.c_ident}}");
528    }
529}
530
531${{self.c_ident}}& operator++(${{self.c_ident}}& e) {
532    assert(e < ${{self.c_ident}}_NUM);
533    return e = ${{self.c_ident}}(e+1);
534}
535''')
536
537        # MachineType hack used to set the base level and number of
538        # components for each Machine
539        if self.isMachineType:
540            code('''
541/** \\brief returns the base vector index for each machine type to be used by NetDest
542  *
543  * \\return the base vector index for each machine type to be used by NetDest
544  * \\see NetDest.hh
545  */
546int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
547{
548    switch(obj) {
549''')
550
551            # For each field
552            code.indent()
553            for i,enum in enumerate(self.enums.itervalues()):
554                code('  case ${{self.c_ident}}_${{enum.ident}}:')
555                code('    return $i;')
556            code.dedent()
557
558            # total num
559            code('''
560      case ${{self.c_ident}}_NUM:
561        return ${{len(self.enums)}};
562
563      default:
564        ERROR_MSG("Invalid range for type ${{self.c_ident}}");
565        return -1;
566    }
567}
568
569/** \\brief returns the machine type for each base vector index used by NetDest
570 *
571 * \\return the MachineTYpe
572 */
573MachineType ${{self.c_ident}}_from_base_level(int type)
574{
575    switch(type) {
576''')
577
578            # For each field
579            code.indent()
580            for i,enum in enumerate(self.enums.itervalues()):
581                code('  case $i:')
582                code('    return ${{self.c_ident}}_${{enum.ident}};')
583            code.dedent()
584
585            # Trailer
586            code('''
587      default:
588        ERROR_MSG("Invalid range for type ${{self.c_ident}}");
589        return MachineType_NUM;
590    }
591}
592
593/** \\brief The return value indicates the number of components created
594 * before a particular machine\'s components
595 *
596 * \\return the base number of components for each machine
597 */
598int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
599{
600    int base = 0;
601    switch(obj) {
602''')
603
604            # For each field
605            code.indent()
606            code('  case ${{self.c_ident}}_NUM:')
607            for enum in reversed(self.enums.values()):
608                code('    base += ${{enum.ident}}_Controller::getNumControllers();')
609                code('  case ${{self.c_ident}}_${{enum.ident}}:')
610            code('    break;')
611            code.dedent()
612
613            code('''
614      default:
615        ERROR_MSG("Invalid range for type ${{self.c_ident}}");
616        return -1;
617    }
618
619    return base;
620}
621
622/** \\brief returns the total number of components for each machine
623 * \\return the total number of components for each machine
624 */
625int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
626{
627    switch(obj) {
628''')
629
630            # For each field
631            for enum in self.enums.itervalues():
632                code('''
633      case ${{self.c_ident}}_${{enum.ident}}:
634        return ${{enum.ident}}_Controller::getNumControllers();
635''')
636
637            # total num
638            code('''
639      case ${{self.c_ident}}_NUM:
640      default:
641        ERROR_MSG("Invalid range for type ${{self.c_ident}}");
642        return -1;
643    }
644}
645''')
646
647        # Write the file
648        code.write(path, "%s.cc" % self.c_ident)
649
650__all__ = [ "Type" ]
651