Type.py revision 13709:dd6b7ac5801f
16288Snate@binkert.org# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
26288Snate@binkert.org# Copyright (c) 2009 The Hewlett-Packard Development Company
36288Snate@binkert.org# All rights reserved.
46288Snate@binkert.org#
56288Snate@binkert.org# Redistribution and use in source and binary forms, with or without
66288Snate@binkert.org# modification, are permitted provided that the following conditions are
76288Snate@binkert.org# met: redistributions of source code must retain the above copyright
86288Snate@binkert.org# notice, this list of conditions and the following disclaimer;
96288Snate@binkert.org# redistributions in binary form must reproduce the above copyright
106288Snate@binkert.org# notice, this list of conditions and the following disclaimer in the
116288Snate@binkert.org# documentation and/or other materials provided with the distribution;
126288Snate@binkert.org# neither the name of the copyright holders nor the names of its
136288Snate@binkert.org# contributors may be used to endorse or promote products derived from
146288Snate@binkert.org# this software without specific prior written permission.
156288Snate@binkert.org#
166288Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176288Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186288Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196288Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206288Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216288Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226288Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236288Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246288Snate@binkert.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256288Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266288Snate@binkert.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276288Snate@binkert.org
286145Snate@binkert.orgfrom collections import OrderedDict
296154Snate@binkert.org
308090Snilay@cs.wisc.edufrom slicc.util import PairContainer
318090Snilay@cs.wisc.edufrom slicc.symbols.Symbol import Symbol
328090Snilay@cs.wisc.edufrom slicc.symbols.Var import Var
338090Snilay@cs.wisc.edu
349208Snilay@cs.wisc.educlass DataMember(Var):
358090Snilay@cs.wisc.edu    def __init__(self, symtab, ident, location, type, code, pairs,
368090Snilay@cs.wisc.edu                 machine, init_code):
378090Snilay@cs.wisc.edu        super(DataMember, self).__init__(symtab, ident, location, type,
388090Snilay@cs.wisc.edu                                         code, pairs, machine)
398090Snilay@cs.wisc.edu        self.init_code = init_code
408090Snilay@cs.wisc.edu
418090Snilay@cs.wisc.educlass Enumeration(PairContainer):
429208Snilay@cs.wisc.edu    def __init__(self, ident, pairs):
438090Snilay@cs.wisc.edu        super(Enumeration, self).__init__(pairs)
448090Snilay@cs.wisc.edu        self.ident = ident
458090Snilay@cs.wisc.edu        self.primary = False
468090Snilay@cs.wisc.edu
478090Snilay@cs.wisc.educlass Type(Symbol):
488090Snilay@cs.wisc.edu    def __init__(self, table, ident, location, pairs, machine=None):
498090Snilay@cs.wisc.edu        super(Type, self).__init__(table, ident, location, pairs)
508090Snilay@cs.wisc.edu        self.c_ident = ident
518090Snilay@cs.wisc.edu        self.abstract_ident = ""
528090Snilay@cs.wisc.edu        if machine:
538090Snilay@cs.wisc.edu            if self.isExternal or self.isPrimitive:
548090Snilay@cs.wisc.edu                if "external_name" in self:
558090Snilay@cs.wisc.edu                    self.c_ident = self["external_name"]
568090Snilay@cs.wisc.edu            else:
578090Snilay@cs.wisc.edu                # Append with machine name
588090Snilay@cs.wisc.edu                self.c_ident = "%s_%s" % (machine, ident)
598090Snilay@cs.wisc.edu
608090Snilay@cs.wisc.edu        self.pairs.setdefault("desc", "No description avaliable")
618090Snilay@cs.wisc.edu
628090Snilay@cs.wisc.edu        # check for interface that this Type implements
638090Snilay@cs.wisc.edu        if "interface" in self:
648090Snilay@cs.wisc.edu            interface = self["interface"]
658090Snilay@cs.wisc.edu            if interface in ("Message"):
668090Snilay@cs.wisc.edu                self["message"] = "yes"
678090Snilay@cs.wisc.edu
688090Snilay@cs.wisc.edu        # FIXME - all of the following id comparisons are fragile hacks
698090Snilay@cs.wisc.edu        if self.ident in ("CacheMemory"):
708090Snilay@cs.wisc.edu            self["cache"] = "yes"
718090Snilay@cs.wisc.edu
728090Snilay@cs.wisc.edu        if self.ident in ("TBETable"):
739208Snilay@cs.wisc.edu            self["tbe"] = "yes"
748090Snilay@cs.wisc.edu
758090Snilay@cs.wisc.edu        if self.ident == "TimerTable":
768090Snilay@cs.wisc.edu            self["timer"] = "yes"
778090Snilay@cs.wisc.edu
788090Snilay@cs.wisc.edu        if self.ident == "DirectoryMemory":
798090Snilay@cs.wisc.edu            self["dir"] = "yes"
808090Snilay@cs.wisc.edu
819208Snilay@cs.wisc.edu        if self.ident == "PersistentTable":
828090Snilay@cs.wisc.edu            self["persistent"] = "yes"
838090Snilay@cs.wisc.edu
848090Snilay@cs.wisc.edu        if self.ident == "Prefetcher":
858090Snilay@cs.wisc.edu            self["prefetcher"] = "yes"
866145Snate@binkert.org
876285Snate@binkert.org        self.isMachineType = (ident == "MachineType")
886285Snate@binkert.org
896145Snate@binkert.org        self.isStateDecl = ("state_decl" in self)
909181Spower.jg@gmail.com        self.statePermPairs = []
917039Snate@binkert.org
926145Snate@binkert.org        self.data_members = OrderedDict()
93        self.methods = {}
94        self.enums = OrderedDict()
95
96    @property
97    def isPrimitive(self):
98        return "primitive" in self
99
100    @property
101    def isMessage(self):
102        return "message" in self
103    @property
104    def isBuffer(self):
105        return "buffer" in self
106    @property
107    def isInPort(self):
108        return "inport" in self
109    @property
110    def isOutPort(self):
111        return "outport" in self
112    @property
113    def isEnumeration(self):
114        return "enumeration" in self
115    @property
116    def isExternal(self):
117        return "external" in self
118    @property
119    def isGlobal(self):
120        return "global" in self
121    @property
122    def isInterface(self):
123        return "interface" in self
124
125    # Return false on error
126    def addDataMember(self, ident, type, pairs, init_code):
127        if ident in self.data_members:
128            return False
129
130        member = DataMember(self.symtab, ident, self.location, type,
131                            "m_%s" % ident, pairs, None, init_code)
132
133        self.data_members[ident] = member
134        self.symtab.registerSym(ident, member)
135        return True
136
137    def dataMemberType(self, ident):
138        return self.data_members[ident].type
139
140    def methodId(self, name, param_type_vec):
141        return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ])
142
143    def methodIdAbstract(self, name, param_type_vec):
144        return '_'.join([name] + [ pt.abstract_ident for pt in param_type_vec ])
145
146    def statePermPairAdd(self, state_name, perm_name):
147        self.statePermPairs.append([state_name, perm_name])
148
149    def addFunc(self, func):
150        ident = self.methodId(func.ident, func.param_types)
151        if ident in self.methods:
152            return False
153
154        self.methods[ident] = func
155        return True
156
157    def addEnum(self, ident, pairs):
158        if ident in self.enums:
159            return False
160
161        self.enums[ident] = Enumeration(ident, pairs)
162
163        # Add default
164        if "default" not in self:
165            self["default"] = "%s_NUM" % self.c_ident
166
167        return True
168
169    ## Used to check if an enum has been already used and therefore
170    ## should not be used again.
171    def checkEnum(self, ident):
172        if ident in self.enums and not self.enums[ident].primary:
173            self.enums[ident].primary = True
174            return True
175        return False
176
177    def writeCodeFiles(self, path, includes):
178        if self.isExternal:
179            # Do nothing
180            pass
181        elif self.isEnumeration:
182            self.printEnumHH(path)
183            self.printEnumCC(path)
184        else:
185            # User defined structs and messages
186            self.printTypeHH(path)
187            self.printTypeCC(path)
188
189    def printTypeHH(self, path):
190        code = self.symtab.codeFormatter()
191        code('''
192/** \\file ${{self.c_ident}}.hh
193 *
194 *
195 * Auto generated C++ code started by $__file__:$__line__
196 */
197
198#ifndef __${{self.c_ident}}_HH__
199#define __${{self.c_ident}}_HH__
200
201#include <iostream>
202
203#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
204''')
205
206        for dm in self.data_members.values():
207            if not dm.type.isPrimitive:
208                code('#include "mem/protocol/$0.hh"', dm.type.c_ident)
209
210        parent = ""
211        if "interface" in self:
212            code('#include "mem/protocol/$0.hh"', self["interface"])
213            parent = " :  public %s" % self["interface"]
214
215        code('''
216$klass ${{self.c_ident}}$parent
217{
218  public:
219    ${{self.c_ident}}
220''', klass="class")
221
222        if self.isMessage:
223            code('(Tick curTime) : %s(curTime) {' % self["interface"])
224        else:
225            code('()\n\t\t{')
226
227        code.indent()
228        if not self.isGlobal:
229            code.indent()
230            for dm in self.data_members.values():
231                ident = dm.ident
232                if "default" in dm:
233                    # look for default value
234                    code('m_$ident = ${{dm["default"]}}; // default for this field')
235                elif "default" in dm.type:
236                    # Look for the type default
237                    tid = dm.type.c_ident
238                    code('m_$ident = ${{dm.type["default"]}}; // default value of $tid')
239                else:
240                    code('// m_$ident has no default')
241            code.dedent()
242        code('}')
243
244        # ******** Copy constructor ********
245        if not self.isGlobal:
246            code('${{self.c_ident}}(const ${{self.c_ident}}&other)')
247
248            # Call superclass constructor
249            if "interface" in self:
250                code('    : ${{self["interface"]}}(other)')
251
252            code('{')
253            code.indent()
254
255            for dm in self.data_members.values():
256                code('m_${{dm.ident}} = other.m_${{dm.ident}};')
257
258            code.dedent()
259            code('}')
260
261        # ******** Full init constructor ********
262        if not self.isGlobal:
263            params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \
264                       for dm in self.data_members.itervalues() ]
265            params = ', '.join(params)
266
267            if self.isMessage:
268                params = "const Tick curTime, " + params
269
270            code('${{self.c_ident}}($params)')
271
272            # Call superclass constructor
273            if "interface" in self:
274                if self.isMessage:
275                    code('    : ${{self["interface"]}}(curTime)')
276                else:
277                    code('    : ${{self["interface"]}}()')
278
279            code('{')
280            code.indent()
281            for dm in self.data_members.values():
282                code('m_${{dm.ident}} = local_${{dm.ident}};')
283
284            code.dedent()
285            code('}')
286
287        # create a clone member
288        if self.isMessage:
289            code('''
290MsgPtr
291clone() const
292{
293     return std::shared_ptr<Message>(new ${{self.c_ident}}(*this));
294}
295''')
296        else:
297            code('''
298${{self.c_ident}}*
299clone() const
300{
301     return new ${{self.c_ident}}(*this);
302}
303''')
304
305        if not self.isGlobal:
306            # const Get methods for each field
307            code('// Const accessors methods for each field')
308            for dm in self.data_members.values():
309                code('''
310/** \\brief Const accessor method for ${{dm.ident}} field.
311 *  \\return ${{dm.ident}} field
312 */
313const ${{dm.type.c_ident}}&
314get${{dm.ident}}() const
315{
316    return m_${{dm.ident}};
317}
318''')
319
320            # Non-const Get methods for each field
321            code('// Non const Accessors methods for each field')
322            for dm in self.data_members.values():
323                code('''
324/** \\brief Non-const accessor method for ${{dm.ident}} field.
325 *  \\return ${{dm.ident}} field
326 */
327${{dm.type.c_ident}}&
328get${{dm.ident}}()
329{
330    return m_${{dm.ident}};
331}
332''')
333
334            #Set methods for each field
335            code('// Mutator methods for each field')
336            for dm in self.data_members.values():
337                code('''
338/** \\brief Mutator method for ${{dm.ident}} field */
339void
340set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}})
341{
342    m_${{dm.ident}} = local_${{dm.ident}};
343}
344''')
345
346        code('void print(std::ostream& out) const;')
347        code.dedent()
348        code('  //private:')
349        code.indent()
350
351        # Data members for each field
352        for dm in self.data_members.values():
353            if "abstract" not in dm:
354                const = ""
355                init = ""
356
357                # global structure
358                if self.isGlobal:
359                    const = "static const "
360
361                # init value
362                if dm.init_code:
363                    # only global structure can have init value here
364                    assert self.isGlobal
365                    init = " = %s" % (dm.init_code)
366
367                if "desc" in dm:
368                    code('/** ${{dm["desc"]}} */')
369
370                code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init;')
371
372        # Prototypes for methods defined for the Type
373        for item in self.methods:
374            proto = self.methods[item].prototype
375            if proto:
376                code('$proto')
377
378        code.dedent()
379        code('};')
380
381        code('''
382inline std::ostream&
383operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
384{
385    obj.print(out);
386    out << std::flush;
387    return out;
388}
389
390#endif // __${{self.c_ident}}_HH__
391''')
392
393        code.write(path, "%s.hh" % self.c_ident)
394
395    def printTypeCC(self, path):
396        code = self.symtab.codeFormatter()
397
398        code('''
399/** \\file ${{self.c_ident}}.cc
400 *
401 * Auto generated C++ code started by $__file__:$__line__
402 */
403
404#include <iostream>
405#include <memory>
406
407#include "mem/protocol/${{self.c_ident}}.hh"
408#include "mem/ruby/system/RubySystem.hh"
409
410using namespace std;
411''')
412
413        code('''
414/** \\brief Print the state of this object */
415void
416${{self.c_ident}}::print(ostream& out) const
417{
418    out << "[${{self.c_ident}}: ";
419''')
420
421        # For each field
422        code.indent()
423        for dm in self.data_members.values():
424            if dm.type.c_ident == "Addr":
425                code('''
426out << "${{dm.ident}} = " << printAddress(m_${{dm.ident}}) << " ";''')
427            else:
428                code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''')
429
430        code.dedent()
431
432        # Trailer
433        code('''
434    out << "]";
435}''')
436
437        # print the code for the methods in the type
438        for item in self.methods:
439            code(self.methods[item].generateCode())
440
441        code.write(path, "%s.cc" % self.c_ident)
442
443    def printEnumHH(self, path):
444        code = self.symtab.codeFormatter()
445        code('''
446/** \\file ${{self.c_ident}}.hh
447 *
448 * Auto generated C++ code started by $__file__:$__line__
449 */
450
451#ifndef __${{self.c_ident}}_HH__
452#define __${{self.c_ident}}_HH__
453
454#include <iostream>
455#include <string>
456
457''')
458        if self.isStateDecl:
459            code('#include "mem/protocol/AccessPermission.hh"')
460
461        if self.isMachineType:
462            code('#include <functional>')
463            code('#include "base/logging.hh"')
464            code('#include "mem/ruby/common/Address.hh"')
465            code('#include "mem/ruby/common/TypeDefines.hh"')
466            code('struct MachineID;')
467
468        code('''
469
470// Class definition
471/** \\enum ${{self.c_ident}}
472 *  \\brief ${{self.desc}}
473 */
474enum ${{self.c_ident}} {
475    ${{self.c_ident}}_FIRST,
476''')
477
478        code.indent()
479        # For each field
480        for i,(ident,enum) in enumerate(self.enums.iteritems()):
481            desc = enum.get("desc", "No description avaliable")
482            if i == 0:
483                init = ' = %s_FIRST' % self.c_ident
484            else:
485                init = ''
486            code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */')
487        code.dedent()
488        code('''
489    ${{self.c_ident}}_NUM
490};
491
492// Code to convert from a string to the enumeration
493${{self.c_ident}} string_to_${{self.c_ident}}(const std::string& str);
494
495// Code to convert state to a string
496std::string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj);
497
498// Code to increment an enumeration type
499${{self.c_ident}} &operator++(${{self.c_ident}} &e);
500''')
501
502        if self.isMachineType:
503            code('''
504
505// define a hash function for the MachineType class
506namespace std {
507template<>
508struct hash<MachineType> {
509    std::size_t operator()(const MachineType &mtype) const {
510        return hash<size_t>()(static_cast<size_t>(mtype));
511    }
512};
513}
514
515''')
516        # MachineType hack used to set the base component id for each Machine
517        if self.isMachineType:
518            code('''
519int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj);
520MachineType ${{self.c_ident}}_from_base_level(int);
521int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj);
522int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj);
523''')
524
525            for enum in self.enums.itervalues():
526                code('''
527
528MachineID get${{enum.ident}}MachineID(NodeID RubyNode);
529''')
530
531        if self.isStateDecl:
532            code('''
533
534// Code to convert the current state to an access permission
535AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj);
536
537''')
538
539        # Trailer
540        code('''
541std::ostream& operator<<(std::ostream& out, const ${{self.c_ident}}& obj);
542
543#endif // __${{self.c_ident}}_HH__
544''')
545
546        code.write(path, "%s.hh" % self.c_ident)
547
548    def printEnumCC(self, path):
549        code = self.symtab.codeFormatter()
550        code('''
551/** \\file ${{self.c_ident}}.hh
552 *
553 * Auto generated C++ code started by $__file__:$__line__
554 */
555
556#include <cassert>
557#include <iostream>
558#include <string>
559
560#include "base/logging.hh"
561#include "mem/protocol/${{self.c_ident}}.hh"
562
563using namespace std;
564
565''')
566
567        if self.isStateDecl:
568            code('''
569// Code to convert the current state to an access permission
570AccessPermission ${{self.c_ident}}_to_permission(const ${{self.c_ident}}& obj)
571{
572    switch(obj) {
573''')
574            # For each case
575            code.indent()
576            for statePerm in self.statePermPairs:
577                code('  case ${{self.c_ident}}_${{statePerm[0]}}:')
578                code('    return AccessPermission_${{statePerm[1]}};')
579            code.dedent()
580            code ('''
581      default:
582        panic("Unknown state access permission converstion for ${{self.c_ident}}");
583    }
584}
585
586''')
587
588        if self.isMachineType:
589            for enum in self.enums.itervalues():
590                if enum.primary:
591                    code('#include "mem/protocol/${{enum.ident}}_Controller.hh"')
592            code('#include "mem/ruby/common/MachineID.hh"')
593
594        code('''
595// Code for output operator
596ostream&
597operator<<(ostream& out, const ${{self.c_ident}}& obj)
598{
599    out << ${{self.c_ident}}_to_string(obj);
600    out << flush;
601    return out;
602}
603
604// Code to convert state to a string
605string
606${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj)
607{
608    switch(obj) {
609''')
610
611        # For each field
612        code.indent()
613        for enum in self.enums.itervalues():
614            code('  case ${{self.c_ident}}_${{enum.ident}}:')
615            code('    return "${{enum.ident}}";')
616        code.dedent()
617
618        # Trailer
619        code('''
620      default:
621        panic("Invalid range for type ${{self.c_ident}}");
622    }
623}
624
625// Code to convert from a string to the enumeration
626${{self.c_ident}}
627string_to_${{self.c_ident}}(const string& str)
628{
629''')
630
631        # For each field
632        start = ""
633        code.indent()
634        for enum in self.enums.itervalues():
635            code('${start}if (str == "${{enum.ident}}") {')
636            code('    return ${{self.c_ident}}_${{enum.ident}};')
637            start = "} else "
638        code.dedent()
639
640        code('''
641    } else {
642        panic("Invalid string conversion for %s, type ${{self.c_ident}}", str);
643    }
644}
645
646// Code to increment an enumeration type
647${{self.c_ident}}&
648operator++(${{self.c_ident}}& e)
649{
650    assert(e < ${{self.c_ident}}_NUM);
651    return e = ${{self.c_ident}}(e+1);
652}
653''')
654
655        # MachineType hack used to set the base level and number of
656        # components for each Machine
657        if self.isMachineType:
658            code('''
659/** \\brief returns the base vector index for each machine type to be
660  * used by NetDest
661  *
662  * \\return the base vector index for each machine type to be used by NetDest
663  * \\see NetDest.hh
664  */
665int
666${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj)
667{
668    switch(obj) {
669''')
670
671            # For each field
672            code.indent()
673            for i,enum in enumerate(self.enums.itervalues()):
674                code('  case ${{self.c_ident}}_${{enum.ident}}:')
675                code('    return $i;')
676            code.dedent()
677
678            # total num
679            code('''
680      case ${{self.c_ident}}_NUM:
681        return ${{len(self.enums)}};
682
683      default:
684        panic("Invalid range for type ${{self.c_ident}}");
685    }
686}
687
688/** \\brief returns the machine type for each base vector index used by NetDest
689 *
690 * \\return the MachineType
691 */
692MachineType
693${{self.c_ident}}_from_base_level(int type)
694{
695    switch(type) {
696''')
697
698            # For each field
699            code.indent()
700            for i,enum in enumerate(self.enums.itervalues()):
701                code('  case $i:')
702                code('    return ${{self.c_ident}}_${{enum.ident}};')
703            code.dedent()
704
705            # Trailer
706            code('''
707      default:
708        panic("Invalid range for type ${{self.c_ident}}");
709    }
710}
711
712/** \\brief The return value indicates the number of components created
713 * before a particular machine\'s components
714 *
715 * \\return the base number of components for each machine
716 */
717int
718${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj)
719{
720    int base = 0;
721    switch(obj) {
722''')
723
724            # For each field
725            code.indent()
726            code('  case ${{self.c_ident}}_NUM:')
727            for enum in reversed(list(self.enums.values())):
728                # Check if there is a defined machine with this type
729                if enum.primary:
730                    code('    base += ${{enum.ident}}_Controller::getNumControllers();')
731                else:
732                    code('    base += 0;')
733                code('    M5_FALLTHROUGH;')
734                code('  case ${{self.c_ident}}_${{enum.ident}}:')
735            code('    break;')
736            code.dedent()
737
738            code('''
739      default:
740        panic("Invalid range for type ${{self.c_ident}}");
741    }
742
743    return base;
744}
745
746/** \\brief returns the total number of components for each machine
747 * \\return the total number of components for each machine
748 */
749int
750${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj)
751{
752    switch(obj) {
753''')
754
755            # For each field
756            for enum in self.enums.itervalues():
757                code('case ${{self.c_ident}}_${{enum.ident}}:')
758                if enum.primary:
759                    code('return ${{enum.ident}}_Controller::getNumControllers();')
760                else:
761                    code('return 0;')
762
763            # total num
764            code('''
765      case ${{self.c_ident}}_NUM:
766      default:
767        panic("Invalid range for type ${{self.c_ident}}");
768    }
769}
770''')
771
772            for enum in self.enums.itervalues():
773                code('''
774
775MachineID
776get${{enum.ident}}MachineID(NodeID RubyNode)
777{
778      MachineID mach = {MachineType_${{enum.ident}}, RubyNode};
779      return mach;
780}
781''')
782
783        # Write the file
784        code.write(path, "%s.cc" % self.c_ident)
785
786__all__ = [ "Type" ]
787