17b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang"""CC code emitter.
27b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
37b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao WangUsed by generators to programatically prepare C++ code. Contains some simple
47b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wangtools that allow generating nicely indented code and do basic correctness
57b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wangchecking.
67b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang"""
77b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
87b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
97b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wangclass Error(Exception):
107b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  """Module level error."""
117b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
127b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
137b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wangclass NamespaceError(Error):
147b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  """Invalid namespace operation."""
157b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
167b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
177b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wangclass HeaderError(Error):
187b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  """Invalid cc header structure."""
197b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
207b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
217b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wangclass CCEmitter(object):
227b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  """Emits c++ code."""
237b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
247b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def __init__(self, debug=False):
257b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.indent = ''
267b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.debug = debug
277b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.namespaces = []
287b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.header_name = None
297b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
307b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def PushIndent(self):
317b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.indent += '  '
327b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
337b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def PopIndent(self):
347b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.indent = self.indent[:-2]
357b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
367b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitIndented(self, what):
377b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    print self.indent + what
387b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
397b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitNewline(self):
407b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    print ''
417b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
427b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitPreprocessor1(self, op, param):
437b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    print '#%s %s' % (op, param)
447b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
457b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitPreprocessor(self, op):
467b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    print '#%s' % op
477b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
487b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitInclude(self, include):
497b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitPreprocessor1('include', include)
507b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
517b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitAssign(self, variable, value):
527b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitBinaryOp(variable, '=', value)
537b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
547b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitAssignIncrement(self, variable, value):
557b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitBinaryOp(variable, '+=', value)
567b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
577b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitBinaryOp(self, operand_1, op, operand_2):
587b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCode('%s %s %s' % (operand_1, op, operand_2))
597b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
607b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitCall(self, function, params=[]):
617b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCode('%s(%s)' % (function, ', '.join(map(str, params))))
627b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
637b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitCode(self, code):
647b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitIndented('%s;' % code)
657b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
667b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitCodeNoSemicolon(self, code):
677b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitIndented('%s' % code)
687b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
697b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitDeclare(self, decl_type, name, value):
707b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitAssign('%s %s' % (decl_type, name), value)
717b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
727b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitAssert(self, assert_expression):
737b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    if self.debug:
747b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      self.EmitCall1('assert', assert_expression)
757b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
767b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitHeaderBegin(self, header_name, includes=None):
777b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    if includes is None:
787b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      includes = []
797b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    if self.header_name:
807b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      raise HeaderError('Header already defined.')
817b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitPreprocessor1('ifndef', (header_name + '_H_').upper())
827b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitPreprocessor1('define', (header_name + '_H_').upper())
837b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitNewline()
847b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    if includes:
857b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      for include in includes:
867b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang        self.EmitInclude(include)
877b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      self.EmitNewline()
887b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.header_name = header_name
897b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
907b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitHeaderEnd(self):
917b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    if not self.header_name:
927b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      raise HeaderError('Header undefined.')
937b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitPreprocessor1('endif',
947b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang                           ' // %s' % (self.header_name + '_H_').upper())
957b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.header_name = None
967b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
977b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitFunctionBeginA(self, function_name, params, return_type):
987b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitIndented('%s %s(%s) {' %
997b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang                      (return_type, function_name,
1007b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang                       ', '.join(['%s %s' % (t, n) for (t, n) in params])))
1017b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.PushIndent()
1027b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1037b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitFunctionEnd(self):
1047b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.PopIndent()
1057b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitIndented('}')
1067b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1077b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitNamespaceBegin(self, namespace):
1087b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCodeNoSemicolon('namespace %s {' % namespace)
1097b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.namespaces.append(namespace)
1107b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1117b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitNamespaceEnd(self):
1127b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    if not self.namespaces:
1137b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      raise NamespaceError('No namespace on stack.')
1147b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCodeNoSemicolon('}  // namespace %s' % self.namespaces.pop())
1157b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1167b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitComment(self, comment):
1177b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitIndented('// ' + comment)
1187b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1197b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitOpenBracket(self, pre_bracket=None):
1207b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    if pre_bracket:
1217b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      self.EmitIndented('%s {' % pre_bracket)
1227b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    else:
1237b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang      self.EmitIndented('{')
1247b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.PushIndent()
1257b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1267b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitCloseBracket(self):
1277b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.PopIndent()
1287b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitIndented('}')
1297b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1307b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitSwitch(self, switch):
1317b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitOpenBracket('switch (%s)' % switch)
1327b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1337b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitSwitchEnd(self):
1347b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCloseBracket()
1357b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1367b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitCase(self, value):
1377b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCodeNoSemicolon('case %s:' % value)
1387b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1397b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitBreak(self):
1407b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCode('break')
1417b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1427b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitIf(self, condition):
1437b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitOpenBracket('if (%s)' % condition)
1447b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1457b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitElse(self):
1467b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.PopIndent()
1477b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCodeNoSemicolon('} else {')
1487b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.PushIndent()
1497b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1507b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def EmitEndif(self):
1517b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    self.EmitCloseBracket()
1527b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang
1537b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang  def Scope(self, scope, value):
1547b05d573cf2e0fd3a58e98cdbfc65153a83fd6f1Miao Wang    return '%s::%s' % (scope, value)
155