Home | History | Annotate | Download | only in generators
      1 """CC code emitter.
      2 
      3 Used by generators to programatically prepare C++ code. Contains some simple
      4 tools that allow generating nicely indented code and do basic correctness
      5 checking.
      6 """
      7 
      8 
      9 class Error(Exception):
     10   """Module level error."""
     11 
     12 
     13 class NamespaceError(Error):
     14   """Invalid namespace operation."""
     15 
     16 
     17 class HeaderError(Error):
     18   """Invalid cc header structure."""
     19 
     20 
     21 class CCEmitter(object):
     22   """Emits c++ code."""
     23 
     24   def __init__(self, debug=False):
     25     self.indent = ''
     26     self.debug = debug
     27     self.namespaces = []
     28     self.header_name = None
     29 
     30   def PushIndent(self):
     31     self.indent += '  '
     32 
     33   def PopIndent(self):
     34     self.indent = self.indent[:-2]
     35 
     36   def EmitIndented(self, what):
     37     print self.indent + what
     38 
     39   def EmitNewline(self):
     40     print ''
     41 
     42   def EmitPreprocessor1(self, op, param):
     43     print '#%s %s' % (op, param)
     44 
     45   def EmitPreprocessor(self, op):
     46     print '#%s' % op
     47 
     48   def EmitInclude(self, include):
     49     self.EmitPreprocessor1('include', include)
     50 
     51   def EmitAssign(self, variable, value):
     52     self.EmitBinaryOp(variable, '=', value)
     53 
     54   def EmitAssignIncrement(self, variable, value):
     55     self.EmitBinaryOp(variable, '+=', value)
     56 
     57   def EmitBinaryOp(self, operand_1, op, operand_2):
     58     self.EmitCode('%s %s %s' % (operand_1, op, operand_2))
     59 
     60   def EmitCall(self, function, params=[]):
     61     self.EmitCode('%s(%s)' % (function, ', '.join(map(str, params))))
     62 
     63   def EmitCode(self, code):
     64     self.EmitIndented('%s;' % code)
     65 
     66   def EmitCodeNoSemicolon(self, code):
     67     self.EmitIndented('%s' % code)
     68 
     69   def EmitDeclare(self, decl_type, name, value):
     70     self.EmitAssign('%s %s' % (decl_type, name), value)
     71 
     72   def EmitAssert(self, assert_expression):
     73     if self.debug:
     74       self.EmitCall1('assert', assert_expression)
     75 
     76   def EmitHeaderBegin(self, header_name, includes=None):
     77     if includes is None:
     78       includes = []
     79     if self.header_name:
     80       raise HeaderError('Header already defined.')
     81     self.EmitPreprocessor1('ifndef', (header_name + '_H_').upper())
     82     self.EmitPreprocessor1('define', (header_name + '_H_').upper())
     83     self.EmitNewline()
     84     if includes:
     85       for include in includes:
     86         self.EmitInclude(include)
     87       self.EmitNewline()
     88     self.header_name = header_name
     89 
     90   def EmitHeaderEnd(self):
     91     if not self.header_name:
     92       raise HeaderError('Header undefined.')
     93     self.EmitPreprocessor1('endif',
     94                            ' // %s' % (self.header_name + '_H_').upper())
     95     self.header_name = None
     96 
     97   def EmitFunctionBeginA(self, function_name, params, return_type):
     98     self.EmitIndented('%s %s(%s) {' %
     99                       (return_type, function_name,
    100                        ', '.join(['%s %s' % (t, n) for (t, n) in params])))
    101     self.PushIndent()
    102 
    103   def EmitFunctionEnd(self):
    104     self.PopIndent()
    105     self.EmitIndented('}')
    106 
    107   def EmitNamespaceBegin(self, namespace):
    108     self.EmitCodeNoSemicolon('namespace %s {' % namespace)
    109     self.namespaces.append(namespace)
    110 
    111   def EmitNamespaceEnd(self):
    112     if not self.namespaces:
    113       raise NamespaceError('No namespace on stack.')
    114     self.EmitCodeNoSemicolon('}  // namespace %s' % self.namespaces.pop())
    115 
    116   def EmitComment(self, comment):
    117     self.EmitIndented('// ' + comment)
    118 
    119   def EmitOpenBracket(self, pre_bracket=None):
    120     if pre_bracket:
    121       self.EmitIndented('%s {' % pre_bracket)
    122     else:
    123       self.EmitIndented('{')
    124     self.PushIndent()
    125 
    126   def EmitCloseBracket(self):
    127     self.PopIndent()
    128     self.EmitIndented('}')
    129 
    130   def EmitSwitch(self, switch):
    131     self.EmitOpenBracket('switch (%s)' % switch)
    132 
    133   def EmitSwitchEnd(self):
    134     self.EmitCloseBracket()
    135 
    136   def EmitCase(self, value):
    137     self.EmitCodeNoSemicolon('case %s:' % value)
    138 
    139   def EmitBreak(self):
    140     self.EmitCode('break')
    141 
    142   def EmitIf(self, condition):
    143     self.EmitOpenBracket('if (%s)' % condition)
    144 
    145   def EmitElse(self):
    146     self.PopIndent()
    147     self.EmitCodeNoSemicolon('} else {')
    148     self.PushIndent()
    149 
    150   def EmitEndif(self):
    151     self.EmitCloseBracket()
    152 
    153   def Scope(self, scope, value):
    154     return '%s::%s' % (scope, value)
    155