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