blob: cbb5fdb4b7279918d218142c3ac628fdca9aad1e [file] [log] [blame]
"""CC code emitter.
Used by generators to programatically prepare C++ code. Contains some simple
tools that allow generating nicely indented code and do basic correctness
checking.
"""
class Error(Exception):
"""Module level error."""
class NamespaceError(Error):
"""Invalid namespace operation."""
class HeaderError(Error):
"""Invalid cc header structure."""
class CCEmitter(object):
"""Emits c++ code."""
def __init__(self, debug=False):
self.indent = ''
self.debug = debug
self.namespaces = []
self.header_name = None
def PushIndent(self):
self.indent += ' '
def PopIndent(self):
self.indent = self.indent[:-2]
def EmitIndented(self, what):
print self.indent + what
def EmitNewline(self):
print ''
def EmitPreprocessor1(self, op, param):
print '#%s %s' % (op, param)
def EmitPreprocessor(self, op):
print '#%s' % op
def EmitInclude(self, include):
self.EmitPreprocessor1('include', include)
def EmitAssign(self, variable, value):
self.EmitBinaryOp(variable, '=', value)
def EmitAssignIncrement(self, variable, value):
self.EmitBinaryOp(variable, '+=', value)
def EmitBinaryOp(self, operand_1, op, operand_2):
self.EmitCode('%s %s %s' % (operand_1, op, operand_2))
def EmitCall(self, function, params=[]):
self.EmitCode('%s(%s)' % (function, ', '.join(map(str, params))))
def EmitCode(self, code):
self.EmitIndented('%s;' % code)
def EmitCodeNoSemicolon(self, code):
self.EmitIndented('%s' % code)
def EmitDeclare(self, decl_type, name, value):
self.EmitAssign('%s %s' % (decl_type, name), value)
def EmitAssert(self, assert_expression):
if self.debug:
self.EmitCall1('assert', assert_expression)
def EmitHeaderBegin(self, header_name, includes=None):
if includes is None:
includes = []
if self.header_name:
raise HeaderError('Header already defined.')
self.EmitPreprocessor1('ifndef', (header_name + '_H_').upper())
self.EmitPreprocessor1('define', (header_name + '_H_').upper())
self.EmitNewline()
if includes:
for include in includes:
self.EmitInclude(include)
self.EmitNewline()
self.header_name = header_name
def EmitHeaderEnd(self):
if not self.header_name:
raise HeaderError('Header undefined.')
self.EmitPreprocessor1('endif',
' // %s' % (self.header_name + '_H_').upper())
self.header_name = None
def EmitFunctionBeginA(self, function_name, params, return_type):
self.EmitIndented('%s %s(%s) {' %
(return_type, function_name,
', '.join(['%s %s' % (t, n) for (t, n) in params])))
self.PushIndent()
def EmitFunctionEnd(self):
self.PopIndent()
self.EmitIndented('}')
def EmitNamespaceBegin(self, namespace):
self.EmitCodeNoSemicolon('namespace %s {' % namespace)
self.namespaces.append(namespace)
def EmitNamespaceEnd(self):
if not self.namespaces:
raise NamespaceError('No namespace on stack.')
self.EmitCodeNoSemicolon('} // namespace %s' % self.namespaces.pop())
def EmitComment(self, comment):
self.EmitIndented('// ' + comment)
def EmitOpenBracket(self, pre_bracket=None):
if pre_bracket:
self.EmitIndented('%s {' % pre_bracket)
else:
self.EmitIndented('{')
self.PushIndent()
def EmitCloseBracket(self):
self.PopIndent()
self.EmitIndented('}')
def EmitSwitch(self, switch):
self.EmitOpenBracket('switch (%s)' % switch)
def EmitSwitchEnd(self):
self.EmitCloseBracket()
def EmitCase(self, value):
self.EmitCodeNoSemicolon('case %s:' % value)
def EmitBreak(self):
self.EmitCode('break')
def EmitIf(self, condition):
self.EmitOpenBracket('if (%s)' % condition)
def EmitElse(self):
self.PopIndent()
self.EmitCodeNoSemicolon('} else {')
self.PushIndent()
def EmitEndif(self):
self.EmitCloseBracket()
def Scope(self, scope, value):
return '%s::%s' % (scope, value)