| # Copyright 2016 The Gemmlowp Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| """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 ClassError(Error): |
| """Invalid class syntax.""" |
| |
| |
| class CCEmitter(object): |
| """Emits c++ code.""" |
| |
| def __init__(self, debug=False): |
| self.indent = '' |
| self.debug = debug |
| self.namespaces = [] |
| self.classes = [] |
| 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=None): |
| if not params: |
| 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 EmitMemberFunctionBegin(self, class_name, class_template_params, |
| class_specializations, function_name, |
| function_params, return_type): |
| """Emit member function of a template/specialized class.""" |
| if class_template_params or class_specializations: |
| self.EmitIndented('template<%s>' % ', '.join(class_template_params)) |
| |
| if class_specializations: |
| class_name += '<%s>' % ', '.join(map(str, class_specializations)) |
| |
| self.EmitIndented('%s %s::%s(%s) {' % ( |
| return_type, class_name, function_name, |
| ', '.join(['%s %s' % (t, n) for (t, n) in function_params]))) |
| self.PushIndent() |
| |
| def EmitFunctionBegin(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('}') |
| self.EmitNewline() |
| |
| def EmitClassBegin(self, class_name, template_params, specializations, |
| base_classes): |
| """Emit class block header.""" |
| self.classes.append(class_name) |
| if template_params or specializations: |
| self.EmitIndented('template<%s>' % ', '.join(template_params)) |
| |
| class_name_extended = class_name |
| if specializations: |
| class_name_extended += '<%s>' % ', '.join(map(str, specializations)) |
| if base_classes: |
| class_name_extended += ' : ' + ', '.join(base_classes) |
| self.EmitIndented('class %s {' % class_name_extended) |
| self.PushIndent() |
| |
| def EmitClassEnd(self): |
| if not self.classes: |
| raise ClassError('No class on stack.') |
| self.classes.pop() |
| self.PopIndent() |
| self.EmitIndented('};') |
| self.EmitNewline() |
| |
| def EmitAccessModifier(self, modifier): |
| if not self.classes: |
| raise ClassError('No class on stack.') |
| self.PopIndent() |
| self.EmitIndented(' %s:' % modifier) |
| self.PushIndent() |
| |
| 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) |