| """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) |