1# Copyright 2016 The Gemmlowp Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""CC code emitter. 15 16Used by generators to programatically prepare C++ code. Contains some simple 17tools that allow generating nicely indented code and do basic correctness 18checking. 19""" 20 21 22class Error(Exception): 23 """Module level error.""" 24 25 26class NamespaceError(Error): 27 """Invalid namespace operation.""" 28 29 30class HeaderError(Error): 31 """Invalid cc header structure.""" 32 33 34class ClassError(Error): 35 """Invalid class syntax.""" 36 37 38class CCEmitter(object): 39 """Emits c++ code.""" 40 41 def __init__(self, debug=False): 42 self.indent = '' 43 self.debug = debug 44 self.namespaces = [] 45 self.classes = [] 46 self.header_name = None 47 48 def PushIndent(self): 49 self.indent += ' ' 50 51 def PopIndent(self): 52 self.indent = self.indent[:-2] 53 54 def EmitIndented(self, what): 55 print(self.indent + what) 56 57 def EmitNewline(self): 58 print('') 59 60 def EmitPreprocessor1(self, op, param): 61 print('#%s %s' % (op, param)) 62 63 def EmitPreprocessor(self, op): 64 print('#%s' % op) 65 66 def EmitInclude(self, include): 67 self.EmitPreprocessor1('include', include) 68 69 def EmitAssign(self, variable, value): 70 self.EmitBinaryOp(variable, '=', value) 71 72 def EmitAssignIncrement(self, variable, value): 73 self.EmitBinaryOp(variable, '+=', value) 74 75 def EmitBinaryOp(self, operand_1, op, operand_2): 76 self.EmitCode('%s %s %s' % (operand_1, op, operand_2)) 77 78 def EmitCall(self, function, params=None): 79 if not params: 80 params = [] 81 self.EmitCode('%s(%s)' % (function, ', '.join(map(str, params)))) 82 83 def EmitCode(self, code): 84 self.EmitIndented('%s;' % code) 85 86 def EmitCodeNoSemicolon(self, code): 87 self.EmitIndented('%s' % code) 88 89 def EmitDeclare(self, decl_type, name, value): 90 self.EmitAssign('%s %s' % (decl_type, name), value) 91 92 def EmitAssert(self, assert_expression): 93 if self.debug: 94 self.EmitCall1('assert', assert_expression) 95 96 def EmitHeaderBegin(self, header_name, includes=None): 97 if includes is None: 98 includes = [] 99 if self.header_name: 100 raise HeaderError('Header already defined.') 101 self.EmitPreprocessor1('ifndef', (header_name + '_H_').upper()) 102 self.EmitPreprocessor1('define', (header_name + '_H_').upper()) 103 self.EmitNewline() 104 if includes: 105 for include in includes: 106 self.EmitInclude(include) 107 self.EmitNewline() 108 self.header_name = header_name 109 110 def EmitHeaderEnd(self): 111 if not self.header_name: 112 raise HeaderError('Header undefined.') 113 self.EmitPreprocessor1('endif', 114 ' // %s' % (self.header_name + '_H_').upper()) 115 self.header_name = None 116 117 def EmitMemberFunctionBegin(self, class_name, class_template_params, 118 class_specializations, function_name, 119 function_params, return_type): 120 """Emit member function of a template/specialized class.""" 121 if class_template_params or class_specializations: 122 self.EmitIndented('template<%s>' % ', '.join(class_template_params)) 123 124 if class_specializations: 125 class_name += '<%s>' % ', '.join(map(str, class_specializations)) 126 127 self.EmitIndented('%s %s::%s(%s) {' % ( 128 return_type, class_name, function_name, 129 ', '.join(['%s %s' % (t, n) for (t, n) in function_params]))) 130 self.PushIndent() 131 132 def EmitFunctionBegin(self, function_name, params, return_type): 133 self.EmitIndented('%s %s(%s) {' % 134 (return_type, function_name, 135 ', '.join(['%s %s' % (t, n) for (t, n) in params]))) 136 self.PushIndent() 137 138 def EmitFunctionEnd(self): 139 self.PopIndent() 140 self.EmitIndented('}') 141 self.EmitNewline() 142 143 def EmitClassBegin(self, class_name, template_params, specializations, 144 base_classes): 145 """Emit class block header.""" 146 self.classes.append(class_name) 147 if template_params or specializations: 148 self.EmitIndented('template<%s>' % ', '.join(template_params)) 149 150 class_name_extended = class_name 151 if specializations: 152 class_name_extended += '<%s>' % ', '.join(map(str, specializations)) 153 if base_classes: 154 class_name_extended += ' : ' + ', '.join(base_classes) 155 self.EmitIndented('class %s {' % class_name_extended) 156 self.PushIndent() 157 158 def EmitClassEnd(self): 159 if not self.classes: 160 raise ClassError('No class on stack.') 161 self.classes.pop() 162 self.PopIndent() 163 self.EmitIndented('};') 164 self.EmitNewline() 165 166 def EmitAccessModifier(self, modifier): 167 if not self.classes: 168 raise ClassError('No class on stack.') 169 self.PopIndent() 170 self.EmitIndented(' %s:' % modifier) 171 self.PushIndent() 172 173 def EmitNamespaceBegin(self, namespace): 174 self.EmitCodeNoSemicolon('namespace %s {' % namespace) 175 self.namespaces.append(namespace) 176 177 def EmitNamespaceEnd(self): 178 if not self.namespaces: 179 raise NamespaceError('No namespace on stack.') 180 self.EmitCodeNoSemicolon('} // namespace %s' % self.namespaces.pop()) 181 182 def EmitComment(self, comment): 183 self.EmitIndented('// ' + comment) 184 185 def EmitOpenBracket(self, pre_bracket=None): 186 if pre_bracket: 187 self.EmitIndented('%s {' % pre_bracket) 188 else: 189 self.EmitIndented('{') 190 self.PushIndent() 191 192 def EmitCloseBracket(self): 193 self.PopIndent() 194 self.EmitIndented('}') 195 196 def EmitSwitch(self, switch): 197 self.EmitOpenBracket('switch (%s)' % switch) 198 199 def EmitSwitchEnd(self): 200 self.EmitCloseBracket() 201 202 def EmitCase(self, value): 203 self.EmitCodeNoSemicolon('case %s:' % value) 204 205 def EmitBreak(self): 206 self.EmitCode('break') 207 208 def EmitIf(self, condition): 209 self.EmitOpenBracket('if (%s)' % condition) 210 211 def EmitElse(self): 212 self.PopIndent() 213 self.EmitCodeNoSemicolon('} else {') 214 self.PushIndent() 215 216 def EmitEndif(self): 217 self.EmitCloseBracket() 218 219 def Scope(self, scope, value): 220 return '%s::%s' % (scope, value) 221