Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ppapi / generators / idl_c_proto.py
blobd5c99a7095df73788499ce4088762ee7f90a9b06
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """ Generator for C style prototypes and definitions """
8 import glob
9 import os
10 import sys
12 from idl_log import ErrOut, InfoOut, WarnOut
13 from idl_node import IDLNode
14 from idl_ast import IDLAst
15 from idl_option import GetOption, Option, ParseOptions
16 from idl_parser import ParseFiles
18 Option('cgen_debug', 'Debug generate.')
20 class CGenError(Exception):
21 def __init__(self, msg):
22 self.value = msg
24 def __str__(self):
25 return repr(self.value)
28 def 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
33 out = '%s/*' % tab + ('\n%s *' % tab).join(lines)
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
43 def 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')
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)
60 def GetNodeComments(node, tabs=0):
61 # 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
69 class CGen(object):
70 # TypeMap
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.
76 TypeMap = {
77 'Array': {
78 'in': 'const %s',
79 'inout': '%s',
80 'out': '%s*',
81 'store': '%s',
82 'return': '%s',
83 'ref': '%s*'
85 'Callspec': {
86 'in': '%s',
87 'inout': '%s',
88 'out': '%s',
89 'store': '%s',
90 'return': '%s'
92 'Enum': {
93 'in': '%s',
94 'inout': '%s*',
95 'out': '%s*',
96 'store': '%s',
97 'return': '%s'
99 'Interface': {
100 'in': 'const %s*',
101 'inout': '%s*',
102 'out': '%s**',
103 'return': '%s*',
104 'store': '%s*'
106 'Struct': {
107 'in': 'const %s*',
108 'inout': '%s*',
109 'out': '%s*',
110 'return': ' %s*',
111 'store': '%s',
112 'ref': '%s*'
114 'blob_t': {
115 'in': 'const %s',
116 'inout': '%s',
117 'out': '%s',
118 'return': '%s',
119 'store': '%s'
121 'mem_t': {
122 'in': 'const %s',
123 'inout': '%s',
124 'out': '%s',
125 'return': '%s',
126 'store': '%s'
128 'mem_ptr_t': {
129 'in': 'const %s',
130 'inout': '%s',
131 'out': '%s',
132 'return': '%s',
133 'store': '%s'
135 'str_t': {
136 'in': 'const %s',
137 'inout': '%s',
138 'out': '%s',
139 'return': 'const %s',
140 'store': '%s'
142 'cstr_t': {
143 'in': '%s',
144 'inout': '%s*',
145 'out': '%s*',
146 'return': '%s',
147 'store': '%s'
149 'TypeValue': {
150 'in': '%s',
151 'constptr_in': 'const %s*', # So we can use const* for PP_Var sometimes.
152 'inout': '%s*',
153 'out': '%s*',
154 'return': '%s',
155 'store': '%s'
161 # RemapName
163 # A diction array of PPAPI types that are converted to language specific
164 # types before being returned by by the C generator
166 RemapName = {
167 'blob_t': 'void**',
168 'float_t': 'float',
169 'double_t': 'double',
170 'handle_t': 'int',
171 'mem_t': 'void*',
172 'mem_ptr_t': 'void**',
173 'str_t': 'char*',
174 'cstr_t': 'const char*',
175 'interface_t' : 'const void*'
178 # Tell how to handle pointers to GL types.
179 for gltype in ['GLbitfield', 'GLboolean', 'GLbyte', 'GLclampf',
180 'GLclampx', 'GLenum', 'GLfixed', 'GLfloat', 'GLint',
181 'GLintptr', 'GLshort', 'GLsizei', 'GLsizeiptr',
182 'GLubyte', 'GLuint', 'GLushort']:
183 ptrtype = gltype + '_ptr_t'
184 TypeMap[ptrtype] = {
185 'in': 'const %s',
186 'inout': '%s',
187 'out': '%s',
188 'return': 'const %s',
189 'store': '%s'
191 RemapName[ptrtype] = '%s*' % gltype
193 def __init__(self):
194 self.dbg_depth = 0
197 # Debug Logging functions
199 def Log(self, txt):
200 if not GetOption('cgen_debug'): return
201 tabs = ' ' * self.dbg_depth
202 print '%s%s' % (tabs, txt)
204 def LogEnter(self, txt):
205 if txt: self.Log(txt)
206 self.dbg_depth += 1
208 def LogExit(self, txt):
209 self.dbg_depth -= 1
210 if txt: self.Log(txt)
213 def GetDefine(self, name, value):
214 out = '#define %s %s' % (name, value)
215 if len(out) > 80:
216 out = '#define %s \\\n %s' % (name, value)
217 return '%s\n' % out
220 # Interface strings
222 def GetMacroHelper(self, node):
223 macro = node.GetProperty('macro')
224 if macro: return macro
225 name = node.GetName()
226 name = name.upper()
227 return "%s_INTERFACE" % name
229 def GetInterfaceMacro(self, node, version = None):
230 name = self.GetMacroHelper(node)
231 if version is None:
232 return name
233 return '%s_%s' % (name, str(version).replace('.', '_'))
235 def GetInterfaceString(self, node, version = None):
236 # If an interface name is specified, use that
237 name = node.GetProperty('iname')
238 if not name:
239 # Otherwise, the interface name is the object's name
240 # With '_Dev' replaced by '(Dev)' if it's a Dev interface.
241 name = node.GetName()
242 if name.endswith('_Dev'):
243 name = '%s(Dev)' % name[:-4]
244 if version is None:
245 return name
246 return "%s;%s" % (name, version)
250 # Return the array specification of the object.
252 def GetArraySpec(self, node):
253 assert(node.cls == 'Array')
254 fixed = node.GetProperty('FIXED')
255 if fixed:
256 return '[%s]' % fixed
257 else:
258 return '[]'
261 # GetTypeName
263 # For any valid 'typed' object such as Member or Typedef
264 # the typenode object contains the typename
266 # For a given node return the type name by passing mode.
268 def GetTypeName(self, node, release, prefix=''):
269 self.LogEnter('GetTypeName of %s rel=%s' % (node, release))
271 # For Members, Params, and Typedefs get the type it refers to otherwise
272 # the node in question is it's own type (struct, union etc...)
273 if node.IsA('Member', 'Param', 'Typedef'):
274 typeref = node.GetType(release)
275 else:
276 typeref = node
278 if typeref is None:
279 node.Error('No type at release %s.' % release)
280 raise CGenError('No type for %s' % node)
282 # If the type is a (BuiltIn) Type then return it's name
283 # remapping as needed
284 if typeref.IsA('Type'):
285 name = CGen.RemapName.get(typeref.GetName(), None)
286 if name is None: name = typeref.GetName()
287 name = '%s%s' % (prefix, name)
289 # For Interfaces, use the name + version
290 elif typeref.IsA('Interface'):
291 rel = typeref.first_release[release]
292 name = 'struct %s%s' % (prefix, self.GetStructName(typeref, rel, True))
294 # For structures, preceed with 'struct' or 'union' as appropriate
295 elif typeref.IsA('Struct'):
296 if typeref.GetProperty('union'):
297 name = 'union %s%s' % (prefix, typeref.GetName())
298 else:
299 name = 'struct %s%s' % (prefix, typeref.GetName())
301 # If it's an enum, or typedef then return the Enum's name
302 elif typeref.IsA('Enum', 'Typedef'):
303 if not typeref.LastRelease(release):
304 first = node.first_release[release]
305 ver = '_' + node.GetVersion(first).replace('.','_')
306 else:
307 ver = ''
308 # The enum may have skipped having a typedef, we need prefix with 'enum'.
309 if typeref.GetProperty('notypedef'):
310 name = 'enum %s%s%s' % (prefix, typeref.GetName(), ver)
311 else:
312 name = '%s%s%s' % (prefix, typeref.GetName(), ver)
314 else:
315 raise RuntimeError('Getting name of non-type %s.' % node)
316 self.LogExit('GetTypeName %s is %s' % (node, name))
317 return name
321 # GetRootType
323 # For a given node return basic type of that object. This is
324 # either a 'Type', 'Callspec', or 'Array'
326 def GetRootTypeMode(self, node, release, mode):
327 self.LogEnter('GetRootType of %s' % node)
328 # If it has an array spec, then treat it as an array regardless of type
329 if node.GetOneOf('Array'):
330 rootType = 'Array'
331 # Or if it has a callspec, treat it as a function
332 elif node.GetOneOf('Callspec'):
333 rootType, mode = self.GetRootTypeMode(node.GetType(release), release,
334 'return')
336 # If it's a plain typedef, try that object's root type
337 elif node.IsA('Member', 'Param', 'Typedef'):
338 rootType, mode = self.GetRootTypeMode(node.GetType(release),
339 release, mode)
341 # If it's an Enum, then it's normal passing rules
342 elif node.IsA('Enum'):
343 rootType = node.cls
345 # If it's an Interface or Struct, we may be passing by value
346 elif node.IsA('Interface', 'Struct'):
347 if mode == 'return':
348 if node.GetProperty('returnByValue'):
349 rootType = 'TypeValue'
350 else:
351 rootType = node.cls
352 else:
353 if node.GetProperty('passByValue'):
354 rootType = 'TypeValue'
355 else:
356 rootType = node.cls
358 # If it's an Basic Type, check if it's a special type
359 elif node.IsA('Type'):
360 if node.GetName() in CGen.TypeMap:
361 rootType = node.GetName()
362 else:
363 rootType = 'TypeValue'
364 else:
365 raise RuntimeError('Getting root type of non-type %s.' % node)
366 self.LogExit('RootType is "%s"' % rootType)
367 return rootType, mode
370 def GetTypeByMode(self, node, release, mode):
371 self.LogEnter('GetTypeByMode of %s mode=%s release=%s' %
372 (node, mode, release))
373 name = self.GetTypeName(node, release)
374 ntype, mode = self.GetRootTypeMode(node, release, mode)
375 out = CGen.TypeMap[ntype][mode] % name
376 self.LogExit('GetTypeByMode %s = %s' % (node, out))
377 return out
380 # Get the passing mode of the object (in, out, inout).
381 def GetParamMode(self, node):
382 self.Log('GetParamMode for %s' % node)
383 if node.GetProperty('in'): return 'in'
384 if node.GetProperty('out'): return 'out'
385 if node.GetProperty('inout'): return 'inout'
386 if node.GetProperty('constptr_in'): return 'constptr_in'
387 return 'return'
390 # GetComponents
392 # Returns the signature components of an object as a tuple of
393 # (rtype, name, arrays, callspec) where:
394 # rtype - The store or return type of the object.
395 # name - The name of the object.
396 # arrays - A list of array dimensions as [] or [<fixed_num>].
397 # args - None if not a function, otherwise a list of parameters.
399 def GetComponents(self, node, release, mode):
400 self.LogEnter('GetComponents mode %s for %s %s' % (mode, node, release))
402 # Generate passing type by modifying root type
403 rtype = self.GetTypeByMode(node, release, mode)
404 # If this is an array output, change it from type* foo[] to type** foo.
405 # type* foo[] means an array of pointers to type, which is confusing.
406 arrayspec = [self.GetArraySpec(array) for array in node.GetListOf('Array')]
407 if mode == 'out' and len(arrayspec) == 1 and arrayspec[0] == '[]':
408 rtype += '*'
409 del arrayspec[0]
411 if node.IsA('Enum', 'Interface', 'Struct'):
412 rname = node.GetName()
413 else:
414 rname = node.GetType(release).GetName()
416 if rname in CGen.RemapName:
417 rname = CGen.RemapName[rname]
418 if '%' in rtype:
419 rtype = rtype % rname
420 name = node.GetName()
421 callnode = node.GetOneOf('Callspec')
422 if callnode:
423 callspec = []
424 for param in callnode.GetListOf('Param'):
425 if not param.IsRelease(release):
426 continue
427 mode = self.GetParamMode(param)
428 ptype, pname, parray, pspec = self.GetComponents(param, release, mode)
429 callspec.append((ptype, pname, parray, pspec))
430 else:
431 callspec = None
433 self.LogExit('GetComponents: %s, %s, %s, %s' %
434 (rtype, name, arrayspec, callspec))
435 return (rtype, name, arrayspec, callspec)
438 def Compose(self, rtype, name, arrayspec, callspec, prefix, func_as_ptr,
439 include_name, unsized_as_ptr):
440 self.LogEnter('Compose: %s %s' % (rtype, name))
441 arrayspec = ''.join(arrayspec)
443 # Switch unsized array to a ptr. NOTE: Only last element can be unsized.
444 if unsized_as_ptr and arrayspec[-2:] == '[]':
445 prefix += '*'
446 arrayspec=arrayspec[:-2]
448 if not include_name:
449 name = prefix + arrayspec
450 else:
451 name = prefix + name + arrayspec
452 if callspec is None:
453 out = '%s %s' % (rtype, name)
454 else:
455 params = []
456 for ptype, pname, parray, pspec in callspec:
457 params.append(self.Compose(ptype, pname, parray, pspec, '', True,
458 include_name=True,
459 unsized_as_ptr=unsized_as_ptr))
460 if func_as_ptr:
461 name = '(*%s)' % name
462 if not params:
463 params = ['void']
464 out = '%s %s(%s)' % (rtype, name, ', '.join(params))
465 self.LogExit('Exit Compose: %s' % out)
466 return out
469 # GetSignature
471 # Returns the 'C' style signature of the object
472 # prefix - A prefix for the object's name
473 # func_as_ptr - Formats a function as a function pointer
474 # include_name - If true, include member name in the signature.
475 # If false, leave it out. In any case, prefix is always
476 # included.
477 # include_version - if True, include version in the member name
479 def GetSignature(self, node, release, mode, prefix='', func_as_ptr=True,
480 include_name=True, include_version=False):
481 self.LogEnter('GetSignature %s %s as func=%s' %
482 (node, mode, func_as_ptr))
483 rtype, name, arrayspec, callspec = self.GetComponents(node, release, mode)
484 if include_version:
485 name = self.GetStructName(node, release, True)
487 # If not a callspec (such as a struct) use a ptr instead of []
488 unsized_as_ptr = not callspec
490 out = self.Compose(rtype, name, arrayspec, callspec, prefix,
491 func_as_ptr, include_name, unsized_as_ptr)
493 self.LogExit('Exit GetSignature: %s' % out)
494 return out
496 # Define a Typedef.
497 def DefineTypedef(self, node, releases, prefix='', comment=False):
498 __pychecker__ = 'unusednames=comment'
499 build_list = node.GetUniqueReleases(releases)
501 out = 'typedef %s;\n' % self.GetSignature(node, build_list[-1], 'return',
502 prefix, True,
503 include_version=False)
504 # Version mangle any other versions
505 for index, rel in enumerate(build_list[:-1]):
506 out += '\n'
507 out += 'typedef %s;\n' % self.GetSignature(node, rel, 'return',
508 prefix, True,
509 include_version=True)
510 self.Log('DefineTypedef: %s' % out)
511 return out
513 # Define an Enum.
514 def DefineEnum(self, node, releases, prefix='', comment=False):
515 __pychecker__ = 'unusednames=comment,releases'
516 self.LogEnter('DefineEnum %s' % node)
517 name = '%s%s' % (prefix, node.GetName())
518 notypedef = node.GetProperty('notypedef')
519 unnamed = node.GetProperty('unnamed')
521 if unnamed:
522 out = 'enum {'
523 elif notypedef:
524 out = 'enum %s {' % name
525 else:
526 out = 'typedef enum {'
527 enumlist = []
528 for child in node.GetListOf('EnumItem'):
529 value = child.GetProperty('VALUE')
530 comment_txt = GetNodeComments(child, tabs=1)
531 if value:
532 item_txt = '%s%s = %s' % (prefix, child.GetName(), value)
533 else:
534 item_txt = '%s%s' % (prefix, child.GetName())
535 enumlist.append('%s %s' % (comment_txt, item_txt))
536 self.LogExit('Exit DefineEnum')
538 if unnamed or notypedef:
539 out = '%s\n%s\n};\n' % (out, ',\n'.join(enumlist))
540 else:
541 out = '%s\n%s\n} %s;\n' % (out, ',\n'.join(enumlist), name)
542 return out
544 def DefineMember(self, node, releases, prefix='', comment=False):
545 __pychecker__ = 'unusednames=prefix,comment'
546 release = releases[0]
547 self.LogEnter('DefineMember %s' % node)
548 if node.GetProperty('ref'):
549 out = '%s;' % self.GetSignature(node, release, 'ref', '', True)
550 else:
551 out = '%s;' % self.GetSignature(node, release, 'store', '', True)
552 self.LogExit('Exit DefineMember')
553 return out
555 def GetStructName(self, node, release, include_version=False):
556 suffix = ''
557 if include_version:
558 ver_num = node.GetVersion(release)
559 suffix = ('_%s' % ver_num).replace('.', '_')
560 return node.GetName() + suffix
562 def DefineStructInternals(self, node, release,
563 include_version=False, comment=True):
564 channel = node.GetProperty('FILE').release_map.GetChannel(release)
565 if channel == 'dev':
566 channel_comment = ' /* dev */'
567 else:
568 channel_comment = ''
569 out = ''
570 if node.GetProperty('union'):
571 out += 'union %s {%s\n' % (
572 self.GetStructName(node, release, include_version), channel_comment)
573 else:
574 out += 'struct %s {%s\n' % (
575 self.GetStructName(node, release, include_version), channel_comment)
577 channel = node.GetProperty('FILE').release_map.GetChannel(release)
578 # Generate Member Functions
579 members = []
580 for child in node.GetListOf('Member'):
581 if channel == 'stable' and child.NodeIsDevOnly():
582 continue
583 member = self.Define(child, [release], tabs=1, comment=comment)
584 if not member:
585 continue
586 members.append(member)
587 out += '%s\n};\n' % '\n'.join(members)
588 return out
591 def DefineUnversionedInterface(self, node, rel):
592 out = '\n'
593 if node.GetProperty('force_struct_namespace'):
594 # Duplicate the definition to put it in struct namespace. This
595 # attribute is only for legacy APIs like OpenGLES2 and new APIs
596 # must not use this. See http://crbug.com/411799
597 out += self.DefineStructInternals(node, rel,
598 include_version=False, comment=True)
599 else:
600 # Define an unversioned typedef for the most recent version
601 out += 'typedef struct %s %s;\n' % (
602 self.GetStructName(node, rel, include_version=True),
603 self.GetStructName(node, rel, include_version=False))
604 return out
607 def DefineStruct(self, node, releases, prefix='', comment=False):
608 __pychecker__ = 'unusednames=comment,prefix'
609 self.LogEnter('DefineStruct %s' % node)
610 out = ''
611 build_list = node.GetUniqueReleases(releases)
613 newest_stable = None
614 newest_dev = None
615 for rel in build_list:
616 channel = node.GetProperty('FILE').release_map.GetChannel(rel)
617 if channel == 'stable':
618 newest_stable = rel
619 if channel == 'dev':
620 newest_dev = rel
621 last_rel = build_list[-1]
623 # TODO(bradnelson) : Bug 157017 finish multiversion support
624 if node.IsA('Struct'):
625 if len(build_list) != 1:
626 node.Error('Can not support multiple versions of node.')
627 assert len(build_list) == 1
628 # Build the most recent one versioned, with comments
629 out = self.DefineStructInternals(node, last_rel,
630 include_version=False, comment=True)
632 if node.IsA('Interface'):
633 # Build the most recent one versioned, with comments
634 out = self.DefineStructInternals(node, last_rel,
635 include_version=True, comment=True)
636 if last_rel == newest_stable:
637 out += self.DefineUnversionedInterface(node, last_rel)
639 # Build the rest without comments and with the version number appended
640 for rel in build_list[0:-1]:
641 channel = node.GetProperty('FILE').release_map.GetChannel(rel)
642 # Skip dev channel interface versions that are
643 # Not the newest version, and
644 # Don't have an equivalent stable version.
645 if channel == 'dev' and rel != newest_dev:
646 if not node.DevInterfaceMatchesStable(rel):
647 continue
648 out += '\n' + self.DefineStructInternals(node, rel,
649 include_version=True,
650 comment=False)
651 if rel == newest_stable:
652 out += self.DefineUnversionedInterface(node, rel)
654 self.LogExit('Exit DefineStruct')
655 return out
659 # Copyright and Comment
661 # Generate a comment or copyright block
663 def Copyright(self, node, cpp_style=False):
664 lines = node.GetName().split('\n')
665 if cpp_style:
666 return '//' + '\n//'.join(filter(lambda f: f != '', lines)) + '\n'
667 return CommentLines(lines)
670 def Indent(self, data, tabs=0):
671 """Handles indentation and 80-column line wrapping."""
672 tab = ' ' * tabs
673 lines = []
674 for line in data.split('\n'):
675 # Add indentation
676 line = tab + line
677 space_break = line.rfind(' ', 0, 80)
678 if len(line) <= 80 or 'http://' in line:
679 # Ignore normal line and URLs permitted by the style guide.
680 lines.append(line.rstrip())
681 elif not '(' in line and space_break >= 0:
682 # Break long typedefs on nearest space.
683 lines.append(line[0:space_break])
684 lines.append(' ' + line[space_break + 1:])
685 else:
686 left = line.rfind('(') + 1
687 args = line[left:].split(',')
688 orig_args = args
689 orig_left = left
690 # Try to split on '(arg1)' or '(arg1, arg2)', not '()'
691 while args[0][0] == ')':
692 left = line.rfind('(', 0, left - 1) + 1
693 if left == 0: # No more parens, take the original option
694 args = orig_args
695 left = orig_left
696 break
697 args = line[left:].split(',')
699 line_max = 0
700 for arg in args:
701 if len(arg) > line_max: line_max = len(arg)
703 if left + line_max >= 80:
704 indent = '%s ' % tab
705 args = (',\n%s' % indent).join([arg.strip() for arg in args])
706 lines.append('%s\n%s%s' % (line[:left], indent, args))
707 else:
708 indent = ' ' * (left - 1)
709 args = (',\n%s' % indent).join(args)
710 lines.append('%s%s' % (line[:left], args))
711 return '\n'.join(lines)
714 # Define a top level object.
715 def Define(self, node, releases, tabs=0, prefix='', comment=False):
716 # If this request does not match unique release, or if the release is not
717 # available (possibly deprecated) then skip.
718 unique = node.GetUniqueReleases(releases)
719 if not unique or not node.InReleases(releases):
720 return ''
722 self.LogEnter('Define %s tab=%d prefix="%s"' % (node,tabs,prefix))
723 declmap = dict({
724 'Enum': CGen.DefineEnum,
725 'Function': CGen.DefineMember,
726 'Interface': CGen.DefineStruct,
727 'Member': CGen.DefineMember,
728 'Struct': CGen.DefineStruct,
729 'Typedef': CGen.DefineTypedef
732 out = ''
733 func = declmap.get(node.cls, None)
734 if not func:
735 ErrOut.Log('Failed to define %s named %s' % (node.cls, node.GetName()))
736 define_txt = func(self, node, releases, prefix=prefix, comment=comment)
738 comment_txt = GetNodeComments(node, tabs=0)
739 if comment_txt and comment:
740 out += comment_txt
741 out += define_txt
743 indented_out = self.Indent(out, tabs)
744 self.LogExit('Exit Define')
745 return indented_out
748 # Clean a string representing an object definition and return then string
749 # as a single space delimited set of tokens.
750 def CleanString(instr):
751 instr = instr.strip()
752 instr = instr.split()
753 return ' '.join(instr)
756 # Test a file, by comparing all it's objects, with their comments.
757 def TestFile(filenode):
758 cgen = CGen()
760 errors = 0
761 for node in filenode.GetChildren()[2:]:
762 instr = node.GetOneOf('Comment')
763 if not instr: continue
764 instr.Dump()
765 instr = CleanString(instr.GetName())
767 outstr = cgen.Define(node, releases=['M14'])
768 if GetOption('verbose'):
769 print outstr + '\n'
770 outstr = CleanString(outstr)
772 if instr != outstr:
773 ErrOut.Log('Failed match of\n>>%s<<\nto:\n>>%s<<\nFor:\n' %
774 (instr, outstr))
775 node.Dump(1, comments=True)
776 errors += 1
777 return errors
780 # Build and resolve the AST and compare each file individual.
781 def TestFiles(filenames):
782 if not filenames:
783 idldir = os.path.split(sys.argv[0])[0]
784 idldir = os.path.join(idldir, 'test_cgen', '*.idl')
785 filenames = glob.glob(idldir)
787 filenames = sorted(filenames)
788 ast = ParseFiles(filenames)
790 total_errs = 0
791 for filenode in ast.GetListOf('File'):
792 errs = TestFile(filenode)
793 if errs:
794 ErrOut.Log('%s test failed with %d error(s).' %
795 (filenode.GetName(), errs))
796 total_errs += errs
798 if total_errs:
799 ErrOut.Log('Failed generator test.')
800 else:
801 InfoOut.Log('Passed generator test.')
802 return total_errs
804 def main(args):
805 filenames = ParseOptions(args)
806 if GetOption('test'):
807 return TestFiles(filenames)
808 ast = ParseFiles(filenames)
809 cgen = CGen()
810 for f in ast.GetListOf('File'):
811 if f.GetProperty('ERRORS') > 0:
812 print 'Skipping %s' % f.GetName()
813 continue
814 for node in f.GetChildren()[2:]:
815 print cgen.Define(node, ast.releases, comment=True, prefix='tst_')
818 if __name__ == '__main__':
819 sys.exit(main(sys.argv[1:]))