1"""CC code emitter. 2 3Used by generators to programatically prepare C++ code. Contains some simple 4tools that allow generating nicely indented code and do basic correctness 5checking. 6""" 7 8 9class Error(Exception): 10 """Module level error.""" 11 12 13class NamespaceError(Error): 14 """Invalid namespace operation.""" 15 16 17class HeaderError(Error): 18 """Invalid cc header structure.""" 19 20 21class 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