You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
6.3 KiB
221 lines
6.3 KiB
# 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)
|