blob: 7e49c02d5084a414907be44261dd4205fdac1c15 [file] [log] [blame]
[email protected]2ec654a2012-01-10 17:47:001#!/usr/bin/env python
[email protected]256513872012-01-05 15:41:522# Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]38c0f7e2011-06-02 01:16:303# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6""" Generator for C style prototypes and definitions """
7
8import glob
9import os
10import sys
11
12from idl_log import ErrOut, InfoOut, WarnOut
[email protected]5eef2882011-07-19 00:08:5413from idl_node import IDLNode
14from idl_ast import IDLAst
[email protected]38c0f7e2011-06-02 01:16:3015from idl_option import GetOption, Option, ParseOptions
[email protected]5eef2882011-07-19 00:08:5416from idl_parser import ParseFiles
17
18Option('cgen_debug', 'Debug generate.')
19
20class CGenError(Exception):
21 def __init__(self, msg):
[email protected]dbe50942011-11-09 23:19:1922 self.value = msg
[email protected]5eef2882011-07-19 00:08:5423
24 def __str__(self):
25 return repr(self.value)
[email protected]38c0f7e2011-06-02 01:16:3026
27
[email protected]f7314732011-08-24 23:03:0628def CommentLines(lines, tabs=0):
29 # Generate a C style comment block by prepending the block with '<tab>/*'
30 # and adding a '<tab> *' per line.
31 tab = ' ' * tabs
32
33 out = '%s/*' % tab + ('\n%s *' % tab).join(lines)
34
35 # Add a terminating ' */' unless the last line is blank which would mean it
36 # already has ' *'
37 if not lines[-1]:
38 out += '/\n'
39 else:
40 out += ' */\n'
41 return out
42
43def Comment(node, prefix=None, tabs=0):
44 # Generate a comment block from the provided Comment node.
45 comment = node.GetName()
46 lines = comment.split('\n')
47
48 # If an option prefix is provided, then prepend that to the comment
49 # for this node.
50 if prefix:
51 prefix_lines = prefix.split('\n')
52 # If both the prefix and comment start with a blank line ('*') remove
53 # the extra one.
54 if prefix_lines[0] == '*' and lines[0] == '*':
55 lines = prefix_lines + lines[1:]
56 else:
57 lines = prefix_lines + lines;
58 return CommentLines(lines, tabs)
59
[email protected]406793d2011-11-14 22:26:5460def GetNodeComments(node, tabs=0):
[email protected]f7314732011-08-24 23:03:0661 # Generate a comment block joining all comment nodes which are children of
62 # the provided node.
63 comment_txt = ''
64 for doc in node.GetListOf('Comment'):
65 comment_txt += Comment(doc, tabs=tabs)
66 return comment_txt
67
68
[email protected]5eef2882011-07-19 00:08:5469class CGen(object):
70 # TypeMap
71 #
72 # TypeMap modifies how an object is stored or passed, for example pointers
73 # are passed as 'const' if they are 'in' parameters, and structures are
74 # preceeded by the keyword 'struct' as well as using a pointer.
75 #
76 TypeMap = {
77 'Array': {
78 'in': 'const %s',
[email protected]45e52d412012-02-07 16:43:4079 'inout': '%s',
[email protected]5eef2882011-07-19 00:08:5480 'out': '%s*',
81 'store': '%s',
[email protected]76641b5e2012-12-13 19:47:0882 'return': '%s',
83 'ref': '%s*'
[email protected]5eef2882011-07-19 00:08:5484 },
85 'Callspec': {
86 'in': '%s',
87 'inout': '%s',
88 'out': '%s',
89 'store': '%s',
90 'return': '%s'
91 },
92 'Enum': {
93 'in': '%s',
94 'inout': '%s*',
95 'out': '%s*',
96 'store': '%s',
97 'return': '%s'
98 },
[email protected]98cfdfc2012-10-23 18:10:0299 'Interface': {
100 'in': 'const %s*',
101 'inout': '%s*',
102 'out': '%s**',
103 'return': '%s*',
104 'store': '%s*'
105 },
[email protected]5eef2882011-07-19 00:08:54106 'Struct': {
107 'in': 'const %s*',
108 'inout': '%s*',
109 'out': '%s*',
110 'return': ' %s*',
[email protected]76641b5e2012-12-13 19:47:08111 'store': '%s',
112 'ref': '%s*'
[email protected]5eef2882011-07-19 00:08:54113 },
[email protected]a7f58e82011-09-26 20:53:44114 'blob_t': {
115 'in': 'const %s',
116 'inout': '%s',
117 'out': '%s',
118 'return': '%s',
119 'store': '%s'
120 },
[email protected]5eef2882011-07-19 00:08:54121 'mem_t': {
122 'in': 'const %s',
123 'inout': '%s',
124 'out': '%s',
125 'return': '%s',
126 'store': '%s'
127 },
[email protected]8665d9b2013-09-27 21:28:15128 'mem_ptr_t': {
129 'in': 'const %s',
130 'inout': '%s',
131 'out': '%s',
132 'return': '%s',
133 'store': '%s'
134 },
[email protected]5eef2882011-07-19 00:08:54135 'str_t': {
136 'in': 'const %s',
137 'inout': '%s',
138 'out': '%s',
139 'return': 'const %s',
140 'store': '%s'
141 },
[email protected]4f932f72012-06-18 05:17:54142 'cstr_t': {
143 'in': '%s',
144 'inout': '%s*',
145 'out': '%s*',
146 'return': '%s',
147 'store': '%s'
148 },
[email protected]5eef2882011-07-19 00:08:54149 'TypeValue': {
150 'in': '%s',
151 'inout': '%s*',
152 'out': '%s*',
153 'return': '%s',
154 'store': '%s'
155 },
[email protected]38c0f7e2011-06-02 01:16:30156 }
157
[email protected]38c0f7e2011-06-02 01:16:30158
[email protected]5eef2882011-07-19 00:08:54159 #
160 # RemapName
161 #
162 # A diction array of PPAPI types that are converted to language specific
163 # types before being returned by by the C generator
164 #
165 RemapName = {
[email protected]a7f58e82011-09-26 20:53:44166 'blob_t': 'void**',
[email protected]5eef2882011-07-19 00:08:54167 'float_t': 'float',
168 'double_t': 'double',
169 'handle_t': 'int',
170 'mem_t': 'void*',
[email protected]8665d9b2013-09-27 21:28:15171 'mem_ptr_t': 'void**',
[email protected]5eef2882011-07-19 00:08:54172 'str_t': 'char*',
[email protected]4f932f72012-06-18 05:17:54173 'cstr_t': 'const char*',
[email protected]5eef2882011-07-19 00:08:54174 'interface_t' : 'const void*'
175 }
[email protected]38c0f7e2011-06-02 01:16:30176
[email protected]5eef2882011-07-19 00:08:54177 def __init__(self):
178 self.dbg_depth = 0
[email protected]5eef2882011-07-19 00:08:54179
180 #
181 # Debug Logging functions
182 #
183 def Log(self, txt):
184 if not GetOption('cgen_debug'): return
[email protected]406793d2011-11-14 22:26:54185 tabs = ' ' * self.dbg_depth
[email protected]5eef2882011-07-19 00:08:54186 print '%s%s' % (tabs, txt)
187
188 def LogEnter(self, txt):
189 if txt: self.Log(txt)
190 self.dbg_depth += 1
191
192 def LogExit(self, txt):
193 self.dbg_depth -= 1
194 if txt: self.Log(txt)
195
[email protected]406793d2011-11-14 22:26:54196
197 def GetDefine(self, name, value):
198 out = '#define %s %s' % (name, value)
199 if len(out) > 80:
200 out = '#define %s \\\n %s' % (name, value)
201 return '%s\n' % out
202
203 #
204 # Interface strings
205 #
206 def GetMacroHelper(self, node):
207 macro = node.GetProperty('macro')
208 if macro: return macro
209 name = node.GetName()
210 name = name.upper()
211 return "%s_INTERFACE" % name
212
213 def GetInterfaceMacro(self, node, version = None):
214 name = self.GetMacroHelper(node)
215 if version is None:
216 return name
217 return '%s_%s' % (name, str(version).replace('.', '_'))
218
219 def GetInterfaceString(self, node, version = None):
220 # If an interface name is specified, use that
221 name = node.GetProperty('iname')
222 if not name:
223 # Otherwise, the interface name is the object's name
224 # With '_Dev' replaced by '(Dev)' if it's a Dev interface.
225 name = node.GetName()
226 if name.endswith('_Dev'):
227 name = '%s(Dev)' % name[:-4]
228 if version is None:
229 return name
230 return "%s;%s" % (name, version)
231
232
[email protected]5eef2882011-07-19 00:08:54233 #
234 # Return the array specification of the object.
235 #
236 def GetArraySpec(self, node):
237 assert(node.cls == 'Array')
[email protected]5eef2882011-07-19 00:08:54238 fixed = node.GetProperty('FIXED')
239 if fixed:
240 return '[%s]' % fixed
241 else:
242 return '[]'
243
244 #
245 # GetTypeName
246 #
247 # For any valid 'typed' object such as Member or Typedef
248 # the typenode object contains the typename
249 #
250 # For a given node return the type name by passing mode.
251 #
[email protected]f7314732011-08-24 23:03:06252 def GetTypeName(self, node, release, prefix=''):
253 self.LogEnter('GetTypeName of %s rel=%s' % (node, release))
[email protected]5eef2882011-07-19 00:08:54254
[email protected]f7314732011-08-24 23:03:06255 # For Members, Params, and Typedefs get the type it refers to otherwise
256 # the node in question is it's own type (struct, union etc...)
[email protected]5eef2882011-07-19 00:08:54257 if node.IsA('Member', 'Param', 'Typedef'):
[email protected]f7314732011-08-24 23:03:06258 typeref = node.GetType(release)
[email protected]5eef2882011-07-19 00:08:54259 else:
260 typeref = node
261
262 if typeref is None:
[email protected]98cfdfc2012-10-23 18:10:02263 node.Error('No type at release %s.' % release)
[email protected]5eef2882011-07-19 00:08:54264 raise CGenError('No type for %s' % node)
265
266 # If the type is a (BuiltIn) Type then return it's name
267 # remapping as needed
268 if typeref.IsA('Type'):
269 name = CGen.RemapName.get(typeref.GetName(), None)
270 if name is None: name = typeref.GetName()
271 name = '%s%s' % (prefix, name)
272
[email protected]98cfdfc2012-10-23 18:10:02273 # For Interfaces, use the name + version
274 elif typeref.IsA('Interface'):
275 rel = typeref.first_release[release]
276 name = 'struct %s%s' % (prefix, self.GetStructName(typeref, rel, True))
277
[email protected]5eef2882011-07-19 00:08:54278 # For structures, preceed with 'struct' or 'union' as appropriate
[email protected]98cfdfc2012-10-23 18:10:02279 elif typeref.IsA('Struct'):
[email protected]5eef2882011-07-19 00:08:54280 if typeref.GetProperty('union'):
281 name = 'union %s%s' % (prefix, typeref.GetName())
282 else:
283 name = 'struct %s%s' % (prefix, typeref.GetName())
284
285 # If it's an enum, or typedef then return the Enum's name
286 elif typeref.IsA('Enum', 'Typedef'):
[email protected]3121bc12013-06-28 23:48:44287 if not typeref.LastRelease(release):
288 first = node.first_release[release]
289 ver = '_' + node.GetVersion(first).replace('.','_')
290 else:
291 ver = ''
[email protected]03f41ec2011-11-18 22:53:04292 # The enum may have skipped having a typedef, we need prefix with 'enum'.
293 if typeref.GetProperty('notypedef'):
[email protected]3121bc12013-06-28 23:48:44294 name = 'enum %s%s%s' % (prefix, typeref.GetName(), ver)
[email protected]03f41ec2011-11-18 22:53:04295 else:
[email protected]3121bc12013-06-28 23:48:44296 name = '%s%s%s' % (prefix, typeref.GetName(), ver)
[email protected]5eef2882011-07-19 00:08:54297
298 else:
299 raise RuntimeError('Getting name of non-type %s.' % node)
300 self.LogExit('GetTypeName %s is %s' % (node, name))
301 return name
302
303
304 #
305 # GetRootType
306 #
307 # For a given node return basic type of that object. This is
308 # either a 'Type', 'Callspec', or 'Array'
309 #
[email protected]f7314732011-08-24 23:03:06310 def GetRootTypeMode(self, node, release, mode):
[email protected]5eef2882011-07-19 00:08:54311 self.LogEnter('GetRootType of %s' % node)
312 # If it has an array spec, then treat it as an array regardless of type
313 if node.GetOneOf('Array'):
314 rootType = 'Array'
315 # Or if it has a callspec, treat it as a function
316 elif node.GetOneOf('Callspec'):
[email protected]f7314732011-08-24 23:03:06317 rootType, mode = self.GetRootTypeMode(node.GetType(release), release,
[email protected]5eef2882011-07-19 00:08:54318 'return')
319
320 # If it's a plain typedef, try that object's root type
321 elif node.IsA('Member', 'Param', 'Typedef'):
[email protected]f7314732011-08-24 23:03:06322 rootType, mode = self.GetRootTypeMode(node.GetType(release),
323 release, mode)
[email protected]5eef2882011-07-19 00:08:54324
325 # If it's an Enum, then it's normal passing rules
326 elif node.IsA('Enum'):
327 rootType = node.cls
328
329 # If it's an Interface or Struct, we may be passing by value
330 elif node.IsA('Interface', 'Struct'):
331 if mode == 'return':
332 if node.GetProperty('returnByValue'):
333 rootType = 'TypeValue'
334 else:
335 rootType = node.cls
336 else:
337 if node.GetProperty('passByValue'):
338 rootType = 'TypeValue'
339 else:
340 rootType = node.cls
341
342 # If it's an Basic Type, check if it's a special type
343 elif node.IsA('Type'):
344 if node.GetName() in CGen.TypeMap:
345 rootType = node.GetName()
346 else:
347 rootType = 'TypeValue'
348 else:
349 raise RuntimeError('Getting root type of non-type %s.' % node)
350 self.LogExit('RootType is "%s"' % rootType)
351 return rootType, mode
352
353
[email protected]f7314732011-08-24 23:03:06354 def GetTypeByMode(self, node, release, mode):
355 self.LogEnter('GetTypeByMode of %s mode=%s release=%s' %
356 (node, mode, release))
357 name = self.GetTypeName(node, release)
358 ntype, mode = self.GetRootTypeMode(node, release, mode)
[email protected]ec5af272011-07-19 01:21:53359 out = CGen.TypeMap[ntype][mode] % name
[email protected]5eef2882011-07-19 00:08:54360 self.LogExit('GetTypeByMode %s = %s' % (node, out))
361 return out
362
363
364 # Get the passing mode of the object (in, out, inout).
365 def GetParamMode(self, node):
366 self.Log('GetParamMode for %s' % node)
367 if node.GetProperty('in'): return 'in'
368 if node.GetProperty('out'): return 'out'
369 if node.GetProperty('inout'): return 'inout'
370 return 'return'
371
372 #
373 # GetComponents
374 #
375 # Returns the signature components of an object as a tuple of
376 # (rtype, name, arrays, callspec) where:
377 # rtype - The store or return type of the object.
378 # name - The name of the object.
379 # arrays - A list of array dimensions as [] or [<fixed_num>].
[email protected]2978339a72011-11-30 17:59:14380 # args - None if not a function, otherwise a list of parameters.
[email protected]5eef2882011-07-19 00:08:54381 #
[email protected]f7314732011-08-24 23:03:06382 def GetComponents(self, node, release, mode):
383 self.LogEnter('GetComponents mode %s for %s %s' % (mode, node, release))
[email protected]5eef2882011-07-19 00:08:54384
385 # Generate passing type by modifying root type
[email protected]f7314732011-08-24 23:03:06386 rtype = self.GetTypeByMode(node, release, mode)
[email protected]5eef2882011-07-19 00:08:54387 if node.IsA('Enum', 'Interface', 'Struct'):
388 rname = node.GetName()
389 else:
[email protected]f7314732011-08-24 23:03:06390 rname = node.GetType(release).GetName()
[email protected]5eef2882011-07-19 00:08:54391
392 if rname in CGen.RemapName:
393 rname = CGen.RemapName[rname]
394 if '%' in rtype:
395 rtype = rtype % rname
396 name = node.GetName()
397 arrayspec = [self.GetArraySpec(array) for array in node.GetListOf('Array')]
398 callnode = node.GetOneOf('Callspec')
399 if callnode:
400 callspec = []
401 for param in callnode.GetListOf('Param'):
[email protected]3121bc12013-06-28 23:48:44402 if not param.IsRelease(release):
403 continue
[email protected]5eef2882011-07-19 00:08:54404 mode = self.GetParamMode(param)
[email protected]f7314732011-08-24 23:03:06405 ptype, pname, parray, pspec = self.GetComponents(param, release, mode)
[email protected]5eef2882011-07-19 00:08:54406 callspec.append((ptype, pname, parray, pspec))
407 else:
408 callspec = None
409
410 self.LogExit('GetComponents: %s, %s, %s, %s' %
411 (rtype, name, arrayspec, callspec))
412 return (rtype, name, arrayspec, callspec)
413
414
[email protected]2978339a72011-11-30 17:59:14415 def Compose(self, rtype, name, arrayspec, callspec, prefix, func_as_ptr,
[email protected]c3064ec2013-04-26 23:38:35416 include_name, unsized_as_ptr):
[email protected]5eef2882011-07-19 00:08:54417 self.LogEnter('Compose: %s %s' % (rtype, name))
418 arrayspec = ''.join(arrayspec)
[email protected]76641b5e2012-12-13 19:47:08419
420 # Switch unsized array to a ptr. NOTE: Only last element can be unsized.
421 if unsized_as_ptr and arrayspec[-2:] == '[]':
422 prefix += '*'
423 arrayspec=arrayspec[:-2]
424
[email protected]2978339a72011-11-30 17:59:14425 if not include_name:
426 name = prefix + arrayspec
427 else:
428 name = prefix + name + arrayspec
[email protected]5eef2882011-07-19 00:08:54429 if callspec is None:
430 out = '%s %s' % (rtype, name)
431 else:
432 params = []
433 for ptype, pname, parray, pspec in callspec:
[email protected]2978339a72011-11-30 17:59:14434 params.append(self.Compose(ptype, pname, parray, pspec, '', True,
[email protected]c3064ec2013-04-26 23:38:35435 include_name=True,
[email protected]76641b5e2012-12-13 19:47:08436 unsized_as_ptr=unsized_as_ptr))
[email protected]2978339a72011-11-30 17:59:14437 if func_as_ptr:
[email protected]c3064ec2013-04-26 23:38:35438 name = '(*%s)' % name
[email protected]32eb1c52012-11-29 02:05:31439 if not params:
440 params = ['void']
[email protected]5eef2882011-07-19 00:08:54441 out = '%s %s(%s)' % (rtype, name, ', '.join(params))
442 self.LogExit('Exit Compose: %s' % out)
443 return out
444
445 #
446 # GetSignature
447 #
448 # Returns the 'C' style signature of the object
449 # prefix - A prefix for the object's name
450 # func_as_ptr - Formats a function as a function pointer
[email protected]2978339a72011-11-30 17:59:14451 # include_name - If true, include member name in the signature.
[email protected]c3064ec2013-04-26 23:38:35452 # If false, leave it out. In any case, prefix is always
453 # included.
[email protected]8c311f02012-11-17 16:01:32454 # include_version - if True, include version in the member name
[email protected]5eef2882011-07-19 00:08:54455 #
[email protected]2978339a72011-11-30 17:59:14456 def GetSignature(self, node, release, mode, prefix='', func_as_ptr=True,
[email protected]c3064ec2013-04-26 23:38:35457 include_name=True, include_version=False):
[email protected]2978339a72011-11-30 17:59:14458 self.LogEnter('GetSignature %s %s as func=%s' %
459 (node, mode, func_as_ptr))
[email protected]f7314732011-08-24 23:03:06460 rtype, name, arrayspec, callspec = self.GetComponents(node, release, mode)
[email protected]8c311f02012-11-17 16:01:32461 if include_version:
462 name = self.GetStructName(node, release, True)
[email protected]76641b5e2012-12-13 19:47:08463
464 # If not a callspec (such as a struct) use a ptr instead of []
465 unsized_as_ptr = not callspec
466
[email protected]2978339a72011-11-30 17:59:14467 out = self.Compose(rtype, name, arrayspec, callspec, prefix,
[email protected]c3064ec2013-04-26 23:38:35468 func_as_ptr, include_name, unsized_as_ptr)
[email protected]76641b5e2012-12-13 19:47:08469
[email protected]5eef2882011-07-19 00:08:54470 self.LogExit('Exit GetSignature: %s' % out)
471 return out
472
[email protected]f7314732011-08-24 23:03:06473 # Define a Typedef.
474 def DefineTypedef(self, node, releases, prefix='', comment=False):
[email protected]406793d2011-11-14 22:26:54475 __pychecker__ = 'unusednames=comment'
[email protected]98cfdfc2012-10-23 18:10:02476 build_list = node.GetUniqueReleases(releases)
477
[email protected]3121bc12013-06-28 23:48:44478 out = 'typedef %s;\n' % self.GetSignature(node, build_list[-1], 'return',
479 prefix, True,
480 include_version=False)
481 # Version mangle any other versions
482 for index, rel in enumerate(build_list[:-1]):
483 out += '\n'
484 out += 'typedef %s;\n' % self.GetSignature(node, rel, 'return',
485 prefix, True,
486 include_version=True)
[email protected]5eef2882011-07-19 00:08:54487 self.Log('DefineTypedef: %s' % out)
488 return out
489
490 # Define an Enum.
[email protected]f7314732011-08-24 23:03:06491 def DefineEnum(self, node, releases, prefix='', comment=False):
[email protected]406793d2011-11-14 22:26:54492 __pychecker__ = 'unusednames=comment,releases'
[email protected]5eef2882011-07-19 00:08:54493 self.LogEnter('DefineEnum %s' % node)
[email protected]03f41ec2011-11-18 22:53:04494 name = '%s%s' % (prefix, node.GetName())
495 notypedef = node.GetProperty('notypedef')
496 unnamed = node.GetProperty('unnamed')
[email protected]98cfdfc2012-10-23 18:10:02497
[email protected]5eef2882011-07-19 00:08:54498 if unnamed:
499 out = 'enum {'
[email protected]03f41ec2011-11-18 22:53:04500 elif notypedef:
501 out = 'enum %s {' % name
[email protected]5eef2882011-07-19 00:08:54502 else:
503 out = 'typedef enum {'
[email protected]5eef2882011-07-19 00:08:54504 enumlist = []
505 for child in node.GetListOf('EnumItem'):
506 value = child.GetProperty('VALUE')
[email protected]f7314732011-08-24 23:03:06507 comment_txt = GetNodeComments(child, tabs=1)
[email protected]5eef2882011-07-19 00:08:54508 if value:
509 item_txt = '%s%s = %s' % (prefix, child.GetName(), value)
510 else:
511 item_txt = '%s%s' % (prefix, child.GetName())
512 enumlist.append('%s %s' % (comment_txt, item_txt))
513 self.LogExit('Exit DefineEnum')
514
[email protected]03f41ec2011-11-18 22:53:04515 if unnamed or notypedef:
[email protected]5eef2882011-07-19 00:08:54516 out = '%s\n%s\n};\n' % (out, ',\n'.join(enumlist))
517 else:
518 out = '%s\n%s\n} %s;\n' % (out, ',\n'.join(enumlist), name)
519 return out
520
[email protected]f7314732011-08-24 23:03:06521 def DefineMember(self, node, releases, prefix='', comment=False):
[email protected]406793d2011-11-14 22:26:54522 __pychecker__ = 'unusednames=prefix,comment'
[email protected]f7314732011-08-24 23:03:06523 release = releases[0]
[email protected]5eef2882011-07-19 00:08:54524 self.LogEnter('DefineMember %s' % node)
[email protected]76641b5e2012-12-13 19:47:08525 if node.GetProperty('ref'):
526 out = '%s;' % self.GetSignature(node, release, 'ref', '', True)
527 else:
528 out = '%s;' % self.GetSignature(node, release, 'store', '', True)
[email protected]5eef2882011-07-19 00:08:54529 self.LogExit('Exit DefineMember')
530 return out
531
[email protected]2978339a72011-11-30 17:59:14532 def GetStructName(self, node, release, include_version=False):
533 suffix = ''
534 if include_version:
535 ver_num = node.GetVersion(release)
536 suffix = ('_%s' % ver_num).replace('.', '_')
537 return node.GetName() + suffix
538
539 def DefineStructInternals(self, node, release,
540 include_version=False, comment=True):
[email protected]5eef2882011-07-19 00:08:54541 out = ''
[email protected]5eef2882011-07-19 00:08:54542 if node.GetProperty('union'):
[email protected]2978339a72011-11-30 17:59:14543 out += 'union %s {\n' % (
544 self.GetStructName(node, release, include_version))
[email protected]5eef2882011-07-19 00:08:54545 else:
[email protected]2978339a72011-11-30 17:59:14546 out += 'struct %s {\n' % (
547 self.GetStructName(node, release, include_version))
[email protected]5eef2882011-07-19 00:08:54548
549 # Generate Member Functions
550 members = []
551 for child in node.GetListOf('Member'):
[email protected]e8a83feb2011-08-25 21:04:26552 member = self.Define(child, [release], tabs=1, comment=comment)
[email protected]5eef2882011-07-19 00:08:54553 if not member:
554 continue
555 members.append(member)
556 out += '%s\n};\n' % '\n'.join(members)
[email protected]e8a83feb2011-08-25 21:04:26557 return out
558
559
560 def DefineStruct(self, node, releases, prefix='', comment=False):
[email protected]406793d2011-11-14 22:26:54561 __pychecker__ = 'unusednames=comment,prefix'
[email protected]e8a83feb2011-08-25 21:04:26562 self.LogEnter('DefineStruct %s' % node)
563 out = ''
564 build_list = node.GetUniqueReleases(releases)
565
[email protected]98cfdfc2012-10-23 18:10:02566 # TODO(noelallen) : Bug 157017 finish multiversion support
567 if node.IsA('Struct'):
568 if len(build_list) != 1:
569 node.Error('Can not support multiple versions of node.')
570 assert len(build_list) == 1
571
572
[email protected]256513872012-01-05 15:41:52573 if node.IsA('Interface'):
574 # Build the most recent one versioned, with comments
575 out = self.DefineStructInternals(node, build_list[-1],
576 include_version=True, comment=True)
577
578 # Define an unversioned typedef for the most recent version
579 out += '\ntypedef struct %s %s;\n' % (
580 self.GetStructName(node, build_list[-1], include_version=True),
581 self.GetStructName(node, build_list[-1], include_version=False))
582 else:
583 # Build the most recent one versioned, with comments
584 out = self.DefineStructInternals(node, build_list[-1],
585 include_version=False, comment=True)
586
[email protected]e8a83feb2011-08-25 21:04:26587
588 # Build the rest without comments and with the version number appended
589 for rel in build_list[0:-1]:
[email protected]2978339a72011-11-30 17:59:14590 out += '\n' + self.DefineStructInternals(node, rel,
591 include_version=True,
[email protected]e8a83feb2011-08-25 21:04:26592 comment=False)
593
[email protected]5eef2882011-07-19 00:08:54594 self.LogExit('Exit DefineStruct')
595 return out
596
[email protected]e8a83feb2011-08-25 21:04:26597
[email protected]5eef2882011-07-19 00:08:54598 #
599 # Copyright and Comment
600 #
601 # Generate a comment or copyright block
602 #
[email protected]8c311f02012-11-17 16:01:32603 def Copyright(self, node, cpp_style=False):
[email protected]5eef2882011-07-19 00:08:54604 lines = node.GetName().split('\n')
[email protected]8c311f02012-11-17 16:01:32605 if cpp_style:
606 return '//' + '\n//'.join(filter(lambda f: f != '', lines)) + '\n'
607 return CommentLines(lines)
608
609
610 def Indent(self, data, tabs=0):
611 """Handles indentation and 80-column line wrapping."""
612 tab = ' ' * tabs
613 lines = []
614 for line in data.split('\n'):
615 # Add indentation
616 line = tab + line
[email protected]56de9032013-09-09 22:35:47617 space_break = line.rfind(' ', 0, 80)
618 if len(line) <= 80 or 'http' in line:
619 # Ignore normal line and URLs permitted by the style guide.
[email protected]8c311f02012-11-17 16:01:32620 lines.append(line.rstrip())
[email protected]56de9032013-09-09 22:35:47621 elif not '(' in line and space_break >= 0:
622 # Break long typedefs on nearest space.
623 lines.append(line[0:space_break])
624 lines.append(' ' + line[space_break + 1:])
[email protected]8c311f02012-11-17 16:01:32625 else:
626 left = line.rfind('(') + 1
627 args = line[left:].split(',')
628 orig_args = args
629 orig_left = left
630 # Try to split on '(arg1)' or '(arg1, arg2)', not '()'
631 while args[0][0] == ')':
632 left = line.rfind('(', 0, left - 1) + 1
633 if left == 0: # No more parens, take the original option
634 args = orig_args
635 left = orig_left
636 break
637 args = line[left:].split(',')
638
639 line_max = 0
640 for arg in args:
641 if len(arg) > line_max: line_max = len(arg)
642
643 if left + line_max >= 80:
644 indent = '%s ' % tab
645 args = (',\n%s' % indent).join([arg.strip() for arg in args])
646 lines.append('%s\n%s%s' % (line[:left], indent, args))
647 else:
648 indent = ' ' * (left - 1)
649 args = (',\n%s' % indent).join(args)
650 lines.append('%s%s' % (line[:left], args))
651 return '\n'.join(lines)
[email protected]5eef2882011-07-19 00:08:54652
653
654 # Define a top level object.
[email protected]f7314732011-08-24 23:03:06655 def Define(self, node, releases, tabs=0, prefix='', comment=False):
[email protected]55e1a702012-01-10 17:55:17656 # If this request does not match unique release, or if the release is not
657 # available (possibly deprecated) then skip.
658 unique = node.GetUniqueReleases(releases)
659 if not unique or not node.InReleases(releases):
[email protected]5eef2882011-07-19 00:08:54660 return ''
[email protected]38c0f7e2011-06-02 01:16:30661
[email protected]f7314732011-08-24 23:03:06662 self.LogEnter('Define %s tab=%d prefix="%s"' % (node,tabs,prefix))
[email protected]406793d2011-11-14 22:26:54663 declmap = dict({
664 'Enum': CGen.DefineEnum,
665 'Function': CGen.DefineMember,
666 'Interface': CGen.DefineStruct,
667 'Member': CGen.DefineMember,
668 'Struct': CGen.DefineStruct,
669 'Typedef': CGen.DefineTypedef
670 })
[email protected]f7314732011-08-24 23:03:06671
672 out = ''
[email protected]406793d2011-11-14 22:26:54673 func = declmap.get(node.cls, None)
[email protected]f7314732011-08-24 23:03:06674 if not func:
675 ErrOut.Log('Failed to define %s named %s' % (node.cls, node.GetName()))
676 define_txt = func(self, node, releases, prefix=prefix, comment=comment)
677
678 comment_txt = GetNodeComments(node, tabs=0)
679 if comment_txt and comment:
680 out += comment_txt
681 out += define_txt
682
[email protected]8c311f02012-11-17 16:01:32683 indented_out = self.Indent(out, tabs)
[email protected]f7314732011-08-24 23:03:06684 self.LogExit('Exit Define')
[email protected]8c311f02012-11-17 16:01:32685 return indented_out
686
[email protected]f7314732011-08-24 23:03:06687
[email protected]38c0f7e2011-06-02 01:16:30688# Clean a string representing an object definition and return then string
689# as a single space delimited set of tokens.
690def CleanString(instr):
691 instr = instr.strip()
692 instr = instr.split()
693 return ' '.join(instr)
694
695
696# Test a file, by comparing all it's objects, with their comments.
697def TestFile(filenode):
[email protected]5eef2882011-07-19 00:08:54698 cgen = CGen()
699
[email protected]38c0f7e2011-06-02 01:16:30700 errors = 0
[email protected]5eef2882011-07-19 00:08:54701 for node in filenode.GetChildren()[2:]:
[email protected]38c0f7e2011-06-02 01:16:30702 instr = node.GetOneOf('Comment')
[email protected]5eef2882011-07-19 00:08:54703 if not instr: continue
704 instr.Dump()
705 instr = CleanString(instr.GetName())
[email protected]38c0f7e2011-06-02 01:16:30706
[email protected]f7314732011-08-24 23:03:06707 outstr = cgen.Define(node, releases=['M14'])
[email protected]5eef2882011-07-19 00:08:54708 if GetOption('verbose'):
709 print outstr + '\n'
[email protected]38c0f7e2011-06-02 01:16:30710 outstr = CleanString(outstr)
711
712 if instr != outstr:
[email protected]6faeb202012-12-06 15:43:05713 ErrOut.Log('Failed match of\n>>%s<<\nto:\n>>%s<<\nFor:\n' %
714 (instr, outstr))
[email protected]38c0f7e2011-06-02 01:16:30715 node.Dump(1, comments=True)
716 errors += 1
717 return errors
718
719
[email protected]38c0f7e2011-06-02 01:16:30720# Build and resolve the AST and compare each file individual.
721def TestFiles(filenames):
722 if not filenames:
723 idldir = os.path.split(sys.argv[0])[0]
724 idldir = os.path.join(idldir, 'test_cgen', '*.idl')
725 filenames = glob.glob(idldir)
726
727 filenames = sorted(filenames)
[email protected]5eef2882011-07-19 00:08:54728 ast = ParseFiles(filenames)
[email protected]38c0f7e2011-06-02 01:16:30729
730 total_errs = 0
[email protected]5eef2882011-07-19 00:08:54731 for filenode in ast.GetListOf('File'):
[email protected]38c0f7e2011-06-02 01:16:30732 errs = TestFile(filenode)
733 if errs:
[email protected]5eef2882011-07-19 00:08:54734 ErrOut.Log('%s test failed with %d error(s).' %
735 (filenode.GetName(), errs))
[email protected]38c0f7e2011-06-02 01:16:30736 total_errs += errs
737
738 if total_errs:
[email protected]f0dd202f2011-06-07 01:36:01739 ErrOut.Log('Failed generator test.')
[email protected]38c0f7e2011-06-02 01:16:30740 else:
[email protected]f0dd202f2011-06-07 01:36:01741 InfoOut.Log('Passed generator test.')
[email protected]38c0f7e2011-06-02 01:16:30742 return total_errs
743
[email protected]6faeb202012-12-06 15:43:05744def main(args):
[email protected]38c0f7e2011-06-02 01:16:30745 filenames = ParseOptions(args)
[email protected]5eef2882011-07-19 00:08:54746 if GetOption('test'):
747 return TestFiles(filenames)
748 ast = ParseFiles(filenames)
[email protected]98cfdfc2012-10-23 18:10:02749 cgen = CGen()
[email protected]5eef2882011-07-19 00:08:54750 for f in ast.GetListOf('File'):
751 if f.GetProperty('ERRORS') > 0:
752 print 'Skipping %s' % f.GetName()
753 continue
[email protected]5eef2882011-07-19 00:08:54754 for node in f.GetChildren()[2:]:
[email protected]98cfdfc2012-10-23 18:10:02755 print cgen.Define(node, comment=True, prefix='tst_')
[email protected]5eef2882011-07-19 00:08:54756
[email protected]38c0f7e2011-06-02 01:16:30757
758if __name__ == '__main__':
[email protected]6faeb202012-12-06 15:43:05759 sys.exit(main(sys.argv[1:]))
[email protected]55e1a702012-01-10 17:55:17760